home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / share / hplip / ui / devmgr4.py < prev    next >
Text File  |  2008-10-13  |  111KB  |  3,215 lines

  1. # -*- coding: utf-8 -*-
  2. #
  3. # (c) Copyright 2001-2008 Hewlett-Packard Development Company, L.P.
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 2 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  18. #
  19. # Authors: Don Welch, Pete Parks
  20. #
  21.  
  22. from __future__ import generators
  23.  
  24. # Std Lib
  25. import sys
  26. import time
  27. import os
  28. import gzip
  29. import select
  30. import struct
  31. import threading
  32. import Queue
  33.  
  34. # Local
  35. from base.g import *
  36. from base import device, utils, pml, maint
  37. from prnt import cups
  38. from base.codes import *
  39. from ui_utils import load_pixmap
  40.  
  41. # Qt
  42. from qt import *
  43.  
  44. # Main form
  45. from devmgr4_base import DevMgr4_base
  46.  
  47. # Scrollviews
  48. from scrollview import ScrollView
  49. from scrollprintsettings import ScrollPrintSettingsView
  50.  
  51. # Alignment and ColorCal forms
  52. from alignform import AlignForm
  53. from aligntype6form1 import AlignType6Form1
  54. from aligntype6form2 import AlignType6Form2
  55. from paperedgealignform import PaperEdgeAlignForm
  56. from colorcalform import ColorCalForm # Type 1 color cal
  57. from coloradjform import ColorAdjForm  # Type 5 and 6 color adj
  58. from colorcalform2 import ColorCalForm2 # Type 2 color cal
  59. from colorcal4form import ColorCal4Form # Type 4 color cal
  60. from align10form import Align10Form # Type 10 and 11 alignment
  61.  
  62. # Misc forms
  63. from loadpaperform import LoadPaperForm
  64. from settingsdialog import SettingsDialog
  65. from aboutdlg import AboutDlg
  66. from cleaningform import CleaningForm
  67. from cleaningform2 import CleaningForm2
  68. from waitform import WaitForm
  69. from faxsettingsform import FaxSettingsForm
  70. from nodevicesform import NoDevicesForm
  71. from settingsdialog import SettingsDialog
  72. from aboutdlg import AboutDlg
  73.  
  74. # all in seconds
  75. MIN_AUTO_REFRESH_RATE = 5
  76. MAX_AUTO_REFRESH_RATE = 60
  77. DEF_AUTO_REFRESH_RATE = 30
  78.  
  79.  
  80. devices = {}    # { Device_URI : device.Device(), ... }
  81. devices_lock = threading.RLock()
  82.  
  83. RESPONSE_START = 1
  84. RESPONSE_DONE = 2
  85.  
  86. # ***********************************************************************************
  87. #
  88. # LISTVIEW/UTILITY UI CLASSES
  89. #
  90. # ***********************************************************************************  
  91.  
  92. class IconViewToolTip(QToolTip):
  93.     def __init__(self, parent, tooltip_text):
  94.         QToolTip.__init__(self, parent.viewport())
  95.         self.parent = parent
  96.  
  97.         
  98.     def maybeTip(self, pos):
  99.         abs_coords = QPoint(pos.x() + self.parent.contentsX(), 
  100.             pos.y() + self.parent.contentsY())
  101.  
  102.         item = self.parent.findItem(abs_coords)
  103.  
  104.         if item is not None and item.tooltip_text:
  105.             rel_coords = QRect()
  106.             rel_coords.setX(pos.x())
  107.             rel_coords.setY(pos.y())
  108.             i = item.rect()
  109.             rel_coords.setWidth(i.width())
  110.             rel_coords.setHeight(i.height())
  111.             self.tip(rel_coords, item.tooltip_text)
  112.  
  113.  
  114.  
  115. class FuncViewItem(QIconViewItem):
  116.     def __init__(self, parent, text, pixmap, tooltip_text, cmd):
  117.         QIconViewItem.__init__(self, parent, text, pixmap)
  118.         self.tooltip_text = tooltip_text
  119.         self.cmd = cmd
  120.  
  121.         self.tooltip = IconViewToolTip(parent, tooltip_text)
  122.  
  123.  
  124.  
  125. class DeviceViewItem(QIconViewItem):
  126.     def __init__(self, parent, text, pixmap, device_uri, is_avail=True):
  127.         QIconViewItem.__init__(self, parent, text, pixmap)
  128.         self.device_uri = device_uri
  129.         self.is_avail = is_avail
  130.  
  131.  
  132.  
  133. class SuppliesListViewItem(QListViewItem):
  134.     def __init__(self, parent, pixmap, desc, part_no, level_pixmap, status):
  135.         QListViewItem.__init__(self, parent, '', desc, part_no, '', status)
  136.         self.setPixmap(0, pixmap)
  137.         self.setPixmap(3, level_pixmap)
  138.  
  139.     def paintCell(self, p, cg, c, w, a):
  140.         color = QColorGroup(cg)
  141.         pos = self.listView().itemPos(self)
  142.         h = self.totalHeight()
  143.  
  144.         if (pos/h) % 2:
  145.             color.setColor(QColorGroup.Base,  QColor(220, 228, 249))
  146.  
  147.         QListViewItem.paintCell(self, p, color, c, w, a)        
  148.  
  149.  
  150.  
  151. class PasswordDialog(QDialog):
  152.     def __init__(self,prompt, parent=None, name=None, modal=0, fl=0):
  153.         QDialog.__init__(self,parent,name,modal,fl)
  154.  
  155.         if not name:
  156.             self.setName("PasswordDialog")
  157.  
  158.         passwordDlg_baseLayout = QGridLayout(self,1,1,11,6,"passwordDlg_baseLayout")
  159.  
  160.         self.passwordLineEdit = QLineEdit(self,"passwordLineEdit")
  161.         self.passwordLineEdit.setEchoMode(QLineEdit.Password)
  162.  
  163.         passwordDlg_baseLayout.addMultiCellWidget(self.passwordLineEdit,1,1,0,1)
  164.  
  165.         self.promptTextLabel = QLabel(self,"promptTextLabel")
  166.  
  167.         passwordDlg_baseLayout.addMultiCellWidget(self.promptTextLabel,0,0,0,1)
  168.         spacer1 = QSpacerItem(20,61,QSizePolicy.Minimum,QSizePolicy.Expanding)
  169.         passwordDlg_baseLayout.addItem(spacer1,2,0)
  170.         spacer2 = QSpacerItem(321,20,QSizePolicy.Expanding,QSizePolicy.Minimum)
  171.         passwordDlg_baseLayout.addItem(spacer2,3,0)
  172.  
  173.         self.okPushButton = QPushButton(self,"okPushButton")
  174.  
  175.         passwordDlg_baseLayout.addWidget(self.okPushButton,3,1)
  176.  
  177.         self.languageChange()
  178.  
  179.         self.resize(QSize(420,163).expandedTo(self.minimumSizeHint()))
  180.         self.clearWState(Qt.WState_Polished)
  181.  
  182.         self.connect(self.okPushButton,SIGNAL("clicked()"),self.accept)
  183.         self.connect(self.passwordLineEdit,SIGNAL("returnPressed()"),self.accept)
  184.         self.promptTextLabel.setText(prompt)
  185.  
  186.     def getPassword(self):
  187.         return unicode(self.passwordLineEdit.text())
  188.  
  189.     def languageChange(self):
  190.         self.setCaption(self.__tr("HP Device Manager - Enter Password"))
  191.         self.okPushButton.setText(self.__tr("OK"))
  192.  
  193.     def __tr(self,s,c = None):
  194.         return qApp.translate("PasswordDialog",s,c)
  195.  
  196.  
  197.  
  198. class ScrollDialog(QDialog):
  199.     def __init__(self, scrollview_cls, cur_device, cur_printer, service, 
  200.         parent = None, name=None, modal=0, fl=0):
  201.  
  202.         QDialog.__init__(self,parent,name,modal,fl)
  203.  
  204.         if not name:
  205.             self.setName("ScrollDialog")
  206.  
  207.         self.setSizeGripEnabled(1)
  208.         ScrollDialogLayout = QGridLayout(self,1,1,11,6,"ScrollDialogLayout")
  209.         Layout1 = QHBoxLayout(None,0,6,"Layout1")
  210.         Horizontal_Spacing2 = QSpacerItem(20,20,QSizePolicy.Expanding,QSizePolicy.Minimum)
  211.         Layout1.addItem(Horizontal_Spacing2)
  212.         self.buttonOk = QPushButton(self,"buttonOk")
  213.         self.buttonOk.setAutoDefault(1)
  214.         self.buttonOk.setDefault(1)
  215.         Layout1.addWidget(self.buttonOk)
  216.         ScrollDialogLayout.addLayout(Layout1,1,0)
  217.  
  218.         self.scrollview = scrollview_cls(service, self)
  219.         ScrollDialogLayout.addWidget(self.scrollview,0,0)
  220.  
  221.         self.scrollview.onDeviceChange(cur_device)
  222.         self.scrollview.onPrinterChange(cur_printer)
  223.         self.languageChange()
  224.  
  225.         self.resize(QSize(520,457).expandedTo(self.minimumSizeHint()))
  226.         self.clearWState(Qt.WState_Polished)
  227.         self.connect(self.buttonOk,SIGNAL("clicked()"),self.accept)
  228.  
  229.  
  230.     def languageChange(self):
  231.         self.setCaption(self.__tr("HP Device Manager"))
  232.         self.buttonOk.setText(self.__tr("Close"))
  233.         self.buttonOk.setAccel(QKeySequence(QString.null))
  234.  
  235.     def __tr(self,s,c = None):
  236.         return qApp.translate("ScrollDialog",s,c)
  237.  
  238.  
  239. def showPasswordUI(prompt):
  240.     try:
  241.         dlg = PasswordDialog(prompt, None)
  242.  
  243.         if dlg.exec_loop() == QDialog.Accepted:
  244.             return dlg.getPassword()
  245.  
  246.     finally:
  247.         pass
  248.         
  249.     return ""        
  250.  
  251.  
  252. class StatusListViewItem(QListViewItem):
  253.     def __init__(self, parent, pixmap, ess, tt, event_code, job_id, username):
  254.         QListViewItem.__init__(self, parent, '', ess, tt, event_code, job_id, username)
  255.         self.setPixmap(0, pixmap)
  256.  
  257.     def paintCell(self, p, cg, c, w, a):
  258.         color = QColorGroup(cg)
  259.         pos = self.listView().itemPos(self)
  260.         h = self.totalHeight()
  261.         row = pos/2
  262.  
  263.         if row % 2:
  264.             color.setColor(QColorGroup.Base,  QColor(220, 228, 249))
  265.  
  266.         QListViewItem.paintCell(self, p, color, c, w, a)
  267.  
  268.  
  269.  
  270. class JobListViewItem(QCheckListItem):
  271.     def __init__(self, parent, pixmap, desc, status, job_id):
  272.         QCheckListItem.__init__(self, parent, '', QCheckListItem.CheckBox)
  273.         self.job_id = job_id
  274.         self.setPixmap(1, pixmap)
  275.         self.setText(2, desc)
  276.         self.setText(3, status)
  277.         self.setText(4, job_id)
  278.  
  279.     def paintCell(self, p, cg, c, w, a):
  280.         color = QColorGroup(cg)
  281.         pos = self.listView().itemPos(self)
  282.         h = self.totalHeight()
  283.  
  284.         if (pos/h) % 2:
  285.             color.setColor(QColorGroup.Base,  QColor(220, 228, 249))
  286.  
  287.         QCheckListItem.paintCell(self, p, color, c, w, a)
  288.  
  289.  
  290.  
  291. class JobInfoDialog(QDialog):
  292.     def __init__(self, text, parent=None, name=None, modal=0, fl=0):
  293.         QDialog.__init__(self, parent, name, modal, fl)
  294.  
  295.         if not name:
  296.             self.setName("JobInfoDialog")
  297.  
  298.         Form1Layout = QGridLayout(self,1,1,11,6,"Form1Layout")
  299.         spacer6 = QSpacerItem(371,20,QSizePolicy.Expanding,QSizePolicy.Minimum)
  300.         Form1Layout.addItem(spacer6,1,0)
  301.         self.pushButton4 = QPushButton(self,"pushButton4")
  302.         Form1Layout.addWidget(self.pushButton4,1,1)
  303.         self.textEdit = QTextEdit(self,"textEdit")
  304.         Form1Layout.addMultiCellWidget(self.textEdit,0,0,0,1)
  305.  
  306.         self.languageChange()
  307.  
  308.         self.resize(QSize(571,542).expandedTo(self.minimumSizeHint()))
  309.         self.clearWState(Qt.WState_Polished)
  310.  
  311.         self.connect(self.pushButton4,SIGNAL("clicked()"),self.close)
  312.  
  313.         self.textEdit.setText(text)
  314.  
  315.  
  316.     def languageChange(self):
  317.         self.setCaption(self.__tr("HP Device Manager - Job Log"))
  318.         self.pushButton4.setText(self.__tr("Close"))
  319.  
  320.  
  321.     def __tr(self,s,c = None):
  322.         return qApp.translate("JobInfoDialog",s,c)
  323.  
  324.  
  325. # ***********************************************************************************
  326. #
  327. # DEVICE UPDATE THREAD
  328. #
  329. # ***********************************************************************************
  330.  
  331.  
  332. class UpdateThread(QThread):
  333.     def __init__(self, response_queue=None, request_queue=None):
  334.         self.response_queue = response_queue # update queue -> main window
  335.         self.request_queue = request_queue # main window -> update queue
  336.  
  337.         QThread.__init__(self)
  338.  
  339.     def run(self):
  340.         while True:
  341.             dev = self.request_queue.get(True)
  342.  
  343.             if dev is None:
  344.                 log.debug("Update thread: exit")
  345.                 break
  346.  
  347.             log.debug("Update thread start: %s" % dev.device_uri)
  348.  
  349.             try:
  350.                 #print "THREAD LOCK ACQUIRE"
  351.                 devices_lock.acquire()
  352.                 #print "THREAD LOCK ACQUIRE - OK"
  353.                 self.response_queue.put((RESPONSE_START, dev.device_uri))
  354.                 log.debug(log.bold("Update: %s %s %s" % ("*"*20, dev.device_uri, "*"*20)))
  355.  
  356.                 if dev.supported:
  357.                     try:
  358.                         dev.open()
  359.                     except Error, e:
  360.                         log.warn(e.msg)
  361.  
  362.                     time.sleep(0.1)
  363.  
  364.                     if dev.device_state == DEVICE_STATE_NOT_FOUND:
  365.                         dev.error_state = ERROR_STATE_ERROR
  366.                     else:
  367.                         try:
  368.                             dev.queryDevice()
  369.  
  370.                         except Error, e:
  371.                             log.error("Query device error (%s)." % e.msg)
  372.                             dev.error_state = ERROR_STATE_ERROR
  373.  
  374.             finally:
  375.                 dev.close()
  376.                 #print "THREAD LOCK RELEASE"
  377.                 devices_lock.release()
  378.  
  379.             log.debug("Device state = %d" % dev.device_state)
  380.             log.debug("Status code = %d" % dev.status_code)
  381.             log.debug("Error state = %d" % dev.error_state)
  382.  
  383.             log.debug("Update thread end: %s" % dev.device_uri)
  384.  
  385.             self.response_queue.put((RESPONSE_DONE, dev.device_uri))
  386.  
  387.  
  388. # ***********************************************************************************
  389. #
  390. # MAINWINDOW
  391. #
  392. # ***********************************************************************************
  393.  
  394. class DevMgr4(DevMgr4_base):
  395.     def __init__(self, read_pipe=None, toolbox_version='0.0',
  396.                  initial_device_uri=None, disable_dbus=False,
  397.                  parent=None, name=None, fl = 0):
  398.  
  399.         DevMgr4_base.__init__(self, parent, name, fl)
  400.  
  401.         log.debug("Initializing toolbox UI...")
  402.         log.debug("HPLIP Version: %s" % sys_cfg.hplip.version)
  403.  
  404.         self.disable_dbus = disable_dbus
  405.         self.toolbox_version = toolbox_version
  406.         self.cur_device_uri = user_cfg.last_used.device_uri # Device URI
  407.         self.device_vars = {}
  408.         self.num_devices = 0
  409.         self.cur_device = None
  410.         self.rescanning = False
  411.         self.initial_device_uri = initial_device_uri
  412.  
  413.         # dbus setup
  414.         if not self.disable_dbus:
  415.             self.dbus_avail, self.service = device.init_dbus()
  416.  
  417.             if not self.dbus_avail:
  418.                 self.FailureUI("<b>Error</b><p>hp-systray must be running to get device status. hp-systray requires dbus support. Device status will not be available.")
  419.             else:
  420.                 log.debug("dbus enabled")
  421.  
  422.         else:
  423.             log.debug("dbus disabled")
  424.             self.dbus_avail, self.service = False, None
  425.  
  426.  
  427.         # Update thread setup
  428.         self.request_queue = Queue.Queue()
  429.         self.response_queue = Queue.Queue()
  430.         self.update_thread = UpdateThread(self.response_queue, self.request_queue)
  431.         self.update_thread.start()
  432.  
  433.         # Pipe from toolbox/dbus setup
  434.         self.fmt = "64s64sI32sI64sf"
  435.         self.fmt_size = struct.calcsize(self.fmt)
  436.  
  437.         if read_pipe is not None and not disable_dbus:
  438.             log.debug("Setting up read_pipe")
  439.             self.notifier = QSocketNotifier(read_pipe, QSocketNotifier.Read)
  440.             QObject.connect(self.notifier, SIGNAL("activated(int)"), self.notifier_activated)
  441.  
  442.         # Application icon
  443.         self.setIcon(load_pixmap('prog', '48x48'))
  444.  
  445.         # User settings
  446.         self.user_settings = utils.UserSettings()
  447.         self.cmd_fab = self.user_settings.cmd_fab
  448.         log.debug("FAB command: %s" % self.cmd_fab)
  449.  
  450.         if not self.user_settings.auto_refresh:
  451.             self.autoRefresh.toggle()
  452.  
  453.         # Other initialization
  454.         self.InitPixmaps()
  455.         self.InitMisc()
  456.         self.InitUI()
  457.  
  458.         cups.setPasswordCallback(showPasswordUI)
  459.  
  460.         if not prop.doc_build:
  461.             self.helpContentsAction.setEnabled(False)
  462.  
  463.         self.allow_auto_refresh = True
  464.         QTimer.singleShot(0, self.InitialUpdate)
  465.  
  466.  
  467.     # ***********************************************************************************
  468.     #
  469.     # INIT
  470.     #
  471.     # ***********************************************************************************
  472.  
  473.     def InitPixmaps(self):
  474.         self.func_icons_cached = False
  475.         self.func_icons = {}
  476.         self.device_icons = {}
  477.  
  478.         # TODO: Use Qt pixmap cache for all pixmaps?
  479.  
  480.         # Device icon list overlays
  481.         self.warning_pix = load_pixmap('warning', '16x16')
  482.         self.error_pix = load_pixmap('error', '16x16')
  483.         self.ok_pix = load_pixmap('ok', '16x16')
  484.         self.lowink_pix = load_pixmap('inkdrop', '16x16')
  485.         self.lowtoner_pix = load_pixmap('toner', '16x16')
  486.         self.busy_pix = load_pixmap('busy', '16x16')
  487.         self.lowpaper_pix = load_pixmap('paper', '16x16')
  488.         self.refresh_pix = load_pixmap('refresh', '16x16')
  489.         self.refresh1_pix = load_pixmap('refresh1', '16x16')
  490.         self.fax_icon = load_pixmap('fax2', 'other')
  491.         self.idle_pix = load_pixmap('idle', '16x16')
  492.         self.scan_pix = load_pixmap("scan", '16x16')
  493.         self.print_pix = load_pixmap("print", '16x16')
  494.         self.sendfax_pix =load_pixmap("fax", '16x16')
  495.         self.pcard_pix = load_pixmap("pcard", '16x16')
  496.         self.makecopies_pix = load_pixmap("makecopies", '16x16')
  497.         self.help_pix = load_pixmap("help", '16x16')
  498.  
  499.  
  500.         # pixmaps: (inkjet, laserjet)
  501.         self.SMALL_ICONS = { ERROR_STATE_CLEAR : (None, None),
  502.             ERROR_STATE_BUSY : (self.busy_pix, self.busy_pix),
  503.             ERROR_STATE_ERROR : (self.error_pix, self.error_pix),
  504.             ERROR_STATE_LOW_SUPPLIES : (self.lowink_pix, self.lowtoner_pix),
  505.             ERROR_STATE_OK : (self.ok_pix, self.ok_pix),
  506.             ERROR_STATE_WARNING : (self.warning_pix, self.warning_pix),
  507.             ERROR_STATE_LOW_PAPER: (self.lowpaper_pix, self.lowpaper_pix),
  508.             ERROR_STATE_PRINTING : (self.busy_pix, self.busy_pix),   
  509.             ERROR_STATE_SCANNING : (self.busy_pix, self.busy_pix),
  510.             ERROR_STATE_PHOTOCARD : (self.busy_pix, self.busy_pix),
  511.             ERROR_STATE_FAXING : (self.busy_pix, self.busy_pix),
  512.             ERROR_STATE_COPYING : (self.busy_pix, self.busy_pix),
  513.             ERROR_STATE_REFRESHING : (self.refresh1_pix, self.refresh1_pix),
  514.         }
  515.  
  516.         self.STATUS_ICONS = { ERROR_STATE_CLEAR : (self.idle_pix, self.idle_pix),
  517.               ERROR_STATE_BUSY : (self.busy_pix, self.busy_pix),
  518.               ERROR_STATE_ERROR : (self.error_pix, self.error_pix),
  519.               ERROR_STATE_LOW_SUPPLIES : (self.lowink_pix, self.lowtoner_pix),
  520.               ERROR_STATE_OK : (self.ok_pix, self.ok_pix),
  521.               ERROR_STATE_WARNING : (self.warning_pix, self.warning_pix),
  522.               ERROR_STATE_LOW_PAPER: (self.lowpaper_pix, self.lowpaper_pix),
  523.               ERROR_STATE_PRINTING : (self.print_pix, self.print_pix),
  524.               ERROR_STATE_SCANNING : (self.scan_pix, self.scan_pix),
  525.               ERROR_STATE_PHOTOCARD : (self.pcard_pix, self.print_pix),
  526.               ERROR_STATE_FAXING : (self.sendfax_pix, self.sendfax_pix),
  527.               ERROR_STATE_COPYING :  (self.makecopies_pix, self.makecopies_pix),
  528.             }
  529.  
  530.  
  531.  
  532.     def InitUI(self):
  533.         # Setup device icon list
  534.         self.DeviceList.setAutoArrange(True)
  535.         self.DeviceList.setSorting(True)
  536.  
  537.         # Setup main menu
  538.         self.deviceRescanAction.setIconSet(QIconSet(self.refresh1_pix))
  539.         self.deviceRefreshAll.setIconSet(QIconSet(self.refresh_pix))
  540.         self.deviceInstallAction.setIconSet(QIconSet(load_pixmap('list_add', '16x16')))
  541.         self.deviceRemoveAction.setIconSet(QIconSet(load_pixmap('list_remove', '16x16')))
  542.         self.settingsConfigure.setIconSet(QIconSet(load_pixmap('settings', '16x16')))
  543.         self.helpContentsAction.setIconSet(QIconSet(self.help_pix))
  544.  
  545.         # Setup toolbar
  546.         self.deviceRescanAction.addTo(self.Toolbar)
  547.         self.deviceRefreshAll.addTo(self.Toolbar)
  548.         self.Toolbar.addSeparator()
  549.         self.deviceInstallAction.addTo(self.Toolbar)
  550.         self.deviceRemoveAction.addTo(self.Toolbar)
  551.         self.Toolbar.addSeparator()
  552.         self.settingsConfigure.addTo(self.Toolbar)
  553.         self.helpContentsAction.addTo(self.Toolbar)
  554.  
  555.         # Init tabs/controls
  556.         self.InitFuncsTab()
  557.         self.InitStatusTab()
  558.         self.InitSuppliesTab()
  559.         self.InitPrintSettingsTab()
  560.         self.InitPrintControlTab()
  561.  
  562.         # Resize the splitter so that the device list starts as a single column
  563.         self.splitter2.setSizes([120, 700]) 
  564.  
  565.  
  566.  
  567.     def InitMisc(self):
  568.         self.unit_names = { "year" : (self.__tr("year"), self.__tr("years")),
  569.             "month" : (self.__tr("month"), self.__tr("months")),
  570.             "week" : (self.__tr("week"), self.__tr("weeks")),
  571.             "day" : (self.__tr("day"), self.__tr("days")),
  572.             "hour" : (self.__tr("hour"), self.__tr("hours")),
  573.             "minute" : (self.__tr("minute"), self.__tr("minutes")),
  574.             "second" : (self.__tr("second"), self.__tr("seconds")),
  575.             }
  576.  
  577.         self.num_repr = { 1 : self.__tr("one"),
  578.               2 : self.__tr("two"),
  579.               3 : self.__tr("three"),
  580.               4 : self.__tr("four"),
  581.               5 : self.__tr("five"),
  582.               6 : self.__tr("six"),
  583.               7 : self.__tr("seven"),
  584.               8 : self.__tr("eight"),
  585.               9 : self.__tr("nine"),
  586.               10 : self.__tr("ten"),
  587.               11 : self.__tr("eleven"),
  588.               12 : self.__tr("twelve")
  589.               }
  590.  
  591.  
  592.         self.TabIndex = { self.FunctionsTab: self.UpdateFuncsTab,
  593.                 self.StatusTab: self.UpdateStatusTab,
  594.                 self.SuppliesTab: self.UpdateSuppliesTab,
  595.                 self.PrintSettingsTab: self.UpdatePrintSettingsTab,
  596.                 self.PrintJobsTab: self.UpdatePrintControlTab,
  597.                 }
  598.  
  599.  
  600.     def InitialUpdate(self):
  601.         self.RescanDevices()
  602.  
  603.         cont = True
  604.         if self.initial_device_uri is not None:
  605.             if not self.ActivateDevice(self.initial_device_uri):
  606.                 log.error("Device %s not found" % self.initial_device_uri)
  607.                 cont = False
  608.  
  609.         self.refresh_timer = QTimer(self, "RefreshTimer")
  610.         self.connect(self.refresh_timer, SIGNAL('timeout()'), self.TimedRefresh)
  611.  
  612.         if MIN_AUTO_REFRESH_RATE <= self.user_settings.auto_refresh_rate <= MAX_AUTO_REFRESH_RATE:
  613.             self.refresh_timer.start(self.user_settings.auto_refresh_rate * 1000)
  614.  
  615.         self.update_timer = QTimer(self)
  616.         self.connect(self.update_timer, SIGNAL("timeout()"), self.ThreadUpdate)
  617.         self.update_timer.start(500)
  618.  
  619.  
  620.     def ActivateDevice(self, device_uri):
  621.         log.debug(log.bold("Activate: %s %s %s" % ("*"*20, device_uri, "*"*20)))
  622.         d = self.DeviceList.firstItem()
  623.         found = False
  624.  
  625.         while d is not None:
  626.             if d.device_uri == device_uri:
  627.                 found = True
  628.                 self.DeviceList.setSelected(d, True)
  629.                 self.DeviceList.setCurrentItem(d)
  630.                 break
  631.  
  632.             d = d.nextItem()
  633.  
  634.         return found
  635.         
  636.         
  637.  
  638.     # ***********************************************************************************
  639.     #
  640.     # UPDATES/NOTIFICATIONS
  641.     #
  642.     # ***********************************************************************************
  643.  
  644.     def notifier_activated(self, sock): # dbus message has arrived
  645.         m = ''
  646.         while True:
  647.             ready = select.select([sock], [], [], 0.1)
  648.  
  649.             if ready[0]:
  650.                 m = ''.join([m, os.read(sock, self.fmt_size)])
  651.                 if len(m) == self.fmt_size:
  652.                     if self.cur_device is None or self.rescanning:
  653.                         return                    
  654.  
  655.                     event = device.Event(*struct.unpack(self.fmt, m))
  656.                     desc = device.queryString(event.event_code)
  657.                     error_state = STATUS_TO_ERROR_STATE_MAP.get(event.event_code, ERROR_STATE_CLEAR)
  658.                     log.debug("Status event: %s (%d)" % (event.device_uri, event.event_code))
  659.  
  660.                     if event.event_code > EVENT_MAX_USER_EVENT:
  661.  
  662.                         if event.event_code == EVENT_HISTORY_UPDATE: # 9003
  663.                             log.debug("History update: %s" % event.device_uri)
  664.  
  665.                             if not self.rescanning:
  666.                                 dev = self.findDeviceByURI(event.device_uri)
  667.  
  668.                                 self.UpdateHistory(dev)
  669.                                 self.UpdateDevice(dev)
  670.  
  671.                         elif event.event_code == EVENT_CUPS_QUEUES_CHANGED:
  672.                             pass
  673.  
  674.                         elif event.event_code == EVENT_RAISE_DEVICE_MANAGER: # 9001
  675.                             log.debug("Raise requested")
  676.                             self.showNormal()
  677.                             self.setActiveWindow()
  678.                             self.raiseW()
  679.  
  680.                     else:
  681.                         log.debug("Ignored")
  682.  
  683.             else:
  684.                 break
  685.  
  686.  
  687.     def TimedRefresh(self):
  688.         if not self.rescanning and self.user_settings.auto_refresh and self.allow_auto_refresh:
  689.             log.debug("Refresh timer...")
  690.             self.CleanupChildren()
  691.  
  692.             if self.user_settings.auto_refresh_type == 0:
  693.                 self.RequestDeviceUpdate()
  694.             else:
  695.                 self.RescanDevices()
  696.  
  697.  
  698.     def ThreadUpdate(self): # periodically check for updates from update thread
  699.         if not self.response_queue.empty():
  700.             response_code, device_uri = self.response_queue.get()
  701.  
  702.             if response_code == RESPONSE_START:
  703.                 self.statusBar().message(self.__tr("Updating %1...").arg(device_uri))
  704.                 qApp.processEvents()
  705.  
  706.             elif response_code == RESPONSE_DONE:
  707.                 self.statusBar().message(QString("%1 (%2)").arg(self.cur_device_uri).\
  708.                     arg(', '.join(self.cur_device.cups_printers)))
  709.  
  710.                 dev = self.findDeviceByURI(device_uri)
  711.  
  712.                 if dev is not None:
  713.                     self.UpdateHistory(dev)
  714.                     self.UpdateDevice(dev)
  715.  
  716.                 qApp.processEvents()
  717.  
  718.             if self.response_queue.empty() and self.request_queue.empty():
  719.                 self.UpdateTitle()
  720.                 # Disable thread timer until more items placed in request queue?
  721.  
  722.  
  723.     # ***********************************************************************************
  724.     #
  725.     # TAB/DEVICE CHANGE SLOTS
  726.     #
  727.     # ***********************************************************************************
  728.  
  729.     def Tabs_currentChanged(self, tab=None):
  730.         """ Called when the active tab changes. 
  731.             Update newly displayed tab.
  732.         """
  733.  
  734.         if tab is None:
  735.             tab = self.Tabs.currentPage()
  736.  
  737.         try:
  738.             self.TabIndex[tab]()
  739.         except AttributeError:
  740.             pass
  741.  
  742.     def Tabs_deviceChanged(self, tab=None):
  743.         """ Called when the device changes. 
  744.             Update the currently displayed tab.
  745.         """
  746.         if tab is None:
  747.             tab = self.Tabs.currentPage()
  748.  
  749.         self.TabIndex[tab]() 
  750.  
  751.  
  752.     # ***********************************************************************************
  753.     #
  754.     # DEVICE ICON LIST/DEVICE UPDATE(S)
  755.     #
  756.     # ***********************************************************************************
  757.  
  758.     def DeviceList_onItem(self, a0):
  759.         pass
  760.  
  761.  
  762.     def deviceRescanAction_activated(self):
  763.         self.deviceRescanAction.setEnabled(False)
  764.         self.RequestDeviceUpdate()
  765.         self.deviceRescanAction.setEnabled(True)
  766.  
  767.  
  768.     def deviceRefreshAll_activated(self):
  769.         self.RescanDevices()
  770.  
  771.  
  772.     def DeviceList_clicked(self,a0):
  773.         pass
  774.  
  775.  
  776.     def CreatePixmap(self, dev=None):
  777.         if dev is None:
  778.             dev = self.cur_device
  779.  
  780.         try:
  781.             dev.icon
  782.         except AttributeError:
  783.             dev.icon = "default_printer"
  784.         
  785.         try:
  786.             self.device_icons[dev.icon]
  787.         except:
  788.             self.device_icons[dev.icon] = load_pixmap(dev.icon, 'devices')
  789.  
  790.         pix = self.device_icons[dev.icon]
  791.  
  792.         w, h = pix.width(), pix.height()
  793.         error_state = dev.error_state
  794.         icon = QPixmap(w, h)
  795.         p = QPainter(icon)
  796.         p.eraseRect(0, 0, icon.width(), icon.height())
  797.         p.drawPixmap(0, 0, pix)
  798.  
  799.         try:
  800.             tech_type = dev.tech_type
  801.         except AttributeError:
  802.             tech_type = TECH_TYPE_NONE
  803.  
  804.         if dev.device_type == DEVICE_TYPE_FAX:
  805.             p.drawPixmap(w - self.fax_icon.width(), 0, self.fax_icon)
  806.  
  807.         if error_state != ERROR_STATE_CLEAR:
  808.             if tech_type in (TECH_TYPE_COLOR_INK, TECH_TYPE_MONO_INK):
  809.                 status_icon = self.SMALL_ICONS[error_state][0] # ink
  810.             else:
  811.                 status_icon = self.SMALL_ICONS[error_state][1] # laser
  812.  
  813.             if status_icon is not None:
  814.                 p.drawPixmap(0, 0, status_icon)
  815.  
  816.         p.end()
  817.  
  818.         return icon
  819.  
  820.  
  821.     def DeviceListRefresh(self):
  822.         global devices
  823.         log.debug("Rescanning device list...")
  824.  
  825.         if not self.rescanning:
  826.             self.setCaption(self.__tr("Refreshing Device List - HP Device Manager"))
  827.             self.statusBar().message(self.__tr("Refreshing device list..."))
  828.  
  829.             self.rescanning = True
  830.             self.cups_devices = device.getSupportedCUPSDevices(['hp', 'hpfax'])
  831.  
  832.             devices_lock.acquire()
  833.  
  834.             try:
  835.                 adds = []
  836.                 for d in self.cups_devices:
  837.                     if d not in devices: 
  838.                         adds.append(d)
  839.  
  840.                 log.debug("Adds: %s" % ','.join(adds))
  841.  
  842.                 removals = []
  843.                 for d in devices: 
  844.                     if d not in self.cups_devices:
  845.                         removals.append(d)
  846.  
  847.                 log.debug("Removals (1): %s" % ','.join(removals))
  848.  
  849.                 updates = []
  850.                 for d in devices:
  851.                     if d not in adds and d not in removals:
  852.                         updates.append(d)
  853.  
  854.                 log.debug("Updates: %s" % ','.join(updates))
  855.  
  856.  
  857.                 for d in adds:
  858.                     log.debug("adding: %s" % d)
  859.                     try:
  860.                         dev = device.Device(d, service=self.service, callback=self.callback, 
  861.                   disable_dbus=self.disable_dbus)
  862.                     except Error:
  863.                         log.error("Unexpected error in Device class.")
  864.                         log.exception()
  865.  
  866.                     if not dev.supported:
  867.                         log.debug("Unsupported model - removing device.")
  868.                         removals.append(d)
  869.                         continue
  870.  
  871.                     self.CheckForDeviceSettingsUI(dev)
  872.                     icon = self.CreatePixmap(dev)
  873.  
  874.                     if dev.device_type == DEVICE_TYPE_FAX:
  875.                         DeviceViewItem(self.DeviceList,  self.__tr("%1 (Fax)").arg(dev.model_ui),
  876.                             icon, d)
  877.                     else:
  878.                         if dev.fax_type:
  879.                             DeviceViewItem(self.DeviceList, self.__tr("%1 (Printer)").arg(dev.model_ui),
  880.                                 icon, d)
  881.                         else:
  882.                             DeviceViewItem(self.DeviceList, dev.model_ui,
  883.                                 icon, d)
  884.  
  885.                     devices[d] = dev
  886.  
  887.                 log.debug("Removals (2): %s" % ','.join(removals))
  888.  
  889.                 for d in removals:
  890.                     item = self.DeviceList.firstItem()
  891.                     log.debug("removing: %s" % d)
  892.                     
  893.                     try:
  894.                         del devices[d]
  895.                     except KeyError:
  896.                         pass
  897.                     
  898.  
  899.                     while item is not None:
  900.                         if item.device_uri == d:
  901.                             self.DeviceList.takeItem(item)
  902.                             break
  903.  
  904.                         item = item.nextItem()
  905.  
  906.                     qApp.processEvents()
  907.  
  908.                 self.DeviceList.adjustItems()
  909.                 self.DeviceList.updateGeometry()
  910.                 qApp.processEvents()
  911.  
  912.                 if len(devices):
  913.                     for tab in self.TabIndex:
  914.                         self.Tabs.setTabEnabled(tab, True)                
  915.  
  916.                     if self.cur_device_uri:
  917.                         item = first_item = self.DeviceList.firstItem()
  918.  
  919.                         while item is not None:
  920.                             qApp.processEvents()
  921.                             if item.device_uri == self.cur_device_uri:
  922.                                 self.DeviceList.setCurrentItem(item)
  923.                                 self.DeviceList.setSelected(item, True)
  924.                                 self.statusBar().message(self.cur_device_uri)
  925.                                 break
  926.  
  927.                             item = item.nextItem()
  928.  
  929.                         else:
  930.                             self.cur_device = None
  931.                             self.cur_device_uri = ''
  932.  
  933.                     if self.cur_device is None:
  934.                         self.cur_device_uri = self.DeviceList.firstItem().device_uri
  935.                         self.cur_device = devices[self.cur_device_uri]
  936.                         self.DeviceList.setCurrentItem(self.DeviceList.firstItem())
  937.  
  938.                     self.Tabs.setTabEnabled(self.SuppliesTab, self.cur_device.device_type == DEVICE_TYPE_PRINTER and 
  939.                         self.cur_device.error_state != ERROR_STATE_ERROR)
  940.                         
  941.                     self.UpdatePrinterCombos()  
  942.  
  943.                     user_cfg.last_used.device_uri = self.cur_device_uri
  944.  
  945.                     for d in updates + adds:
  946.                         if d not in removals:
  947.                             self.RequestDeviceUpdate(devices[d])
  948.  
  949.                 else:
  950.                     self.cur_device = None
  951.                     self.deviceRescanAction.setEnabled(False)
  952.                     self.deviceRemoveAction.setEnabled(False)
  953.                     self.rescanning = False
  954.                     self.statusBar().message(self.__tr("Press F6 to refresh."))
  955.  
  956.                     for tab in self.TabIndex:
  957.                         self.Tabs.setTabEnabled(tab, False)
  958.  
  959.                     dlg = NoDevicesForm(self, "", True)
  960.                     dlg.show()
  961.  
  962.             finally:
  963.                 self.rescanning = False
  964.                 devices_lock.release()
  965.  
  966.             self.deviceRescanAction.setEnabled(True)
  967.             self.deviceRemoveAction.setEnabled(True)
  968.  
  969.  
  970.  
  971.     def UpdateTitle(self):
  972.         if self.cur_device.device_type == DEVICE_TYPE_FAX:
  973.                 self.setCaption(self.__tr("HP Device Manager - %1 (Fax)").arg(self.cur_device.model_ui))
  974.         else:
  975.             if self.cur_device.fax_type:    
  976.                 self.setCaption(self.__tr("HP Device Manager - %1 (Printer)").arg(self.cur_device.model_ui))                        
  977.             else:
  978.                 self.setCaption(self.__tr("HP Device Manager - %1").arg(self.cur_device.model_ui)) 
  979.  
  980.  
  981.     def UpdateDeviceByURI(self, device_uri):
  982.         return self.UpdateDevice(self.findDeviceByURI(device_uri))
  983.  
  984.  
  985.     def UpdateDevice(self, dev=None, update_tab=True):
  986.         """ Update the device icon and currently displayed tab.
  987.         """
  988.         if dev is None:
  989.             dev = self.cur_device
  990.  
  991.         log.debug("UpdateDevice(%s)" % dev.device_uri)
  992.  
  993.         item = self.findItem(dev)
  994.  
  995.         if item is not None:
  996.             item.setPixmap(self.CreatePixmap(dev))
  997.  
  998.         if dev is self.cur_device and dev.error_state == ERROR_STATE_ERROR:
  999.             self.Tabs.setCurrentPage(1)
  1000.  
  1001.         if dev is self.cur_device and update_tab:
  1002.             self.UpdatePrinterCombos()
  1003.             self.TabIndex[self.Tabs.currentPage()]()
  1004.  
  1005.         qApp.processEvents()
  1006.  
  1007.  
  1008.     def DeviceList_currentChanged(self, i):
  1009.         if i is not None: # and not self.rescanning:
  1010.             self.cur_device_uri = self.DeviceList.currentItem().device_uri
  1011.             self.cur_device = devices[self.cur_device_uri]
  1012.             user_cfg.last_used.device_uri = self.cur_device_uri
  1013.  
  1014.             self.Tabs.setTabEnabled(self.SuppliesTab, self.cur_device.device_type == DEVICE_TYPE_PRINTER and 
  1015.                 self.cur_device.error_state != ERROR_STATE_ERROR)
  1016.                 
  1017.             self.UpdateDevice()
  1018.             self.UpdateTitle()
  1019.  
  1020.  
  1021.     def findItem(self, dev):
  1022.         if dev is None:
  1023.             dev = self.cur_device
  1024.  
  1025.         return self.findItemByURI(dev.device_uri)
  1026.  
  1027.  
  1028.     def findItemByURI(self, device_uri):
  1029.         item = self.DeviceList.firstItem()
  1030.  
  1031.         while item is not None:
  1032.             if item.device_uri == device_uri:
  1033.                 return item
  1034.             item = item.nextItem()
  1035.  
  1036.  
  1037.     def findDeviceByURI(self, device_uri):
  1038.         try:
  1039.             return devices[device_uri]
  1040.         except:
  1041.             return None
  1042.  
  1043.  
  1044.     def RequestDeviceUpdate(self, dev=None, item=None):
  1045.         """ Submit device update request to update thread. """
  1046.  
  1047.         if dev is None:
  1048.             dev = self.cur_device
  1049.  
  1050.         if dev is not None:
  1051.             #log.debug("RequestDeviceUpdate(%s)" % dev.device_uri)
  1052.             dev.error_state = ERROR_STATE_REFRESHING
  1053.             self.UpdateDevice(dev, update_tab=False)
  1054.             qApp.processEvents()
  1055.  
  1056.             self.request_queue.put(dev)
  1057.  
  1058.  
  1059.     def RescanDevices(self):
  1060.         #log.debug("RescanDevices()")
  1061.         if not self.rescanning:
  1062.             self.deviceRefreshAll.setEnabled(False)
  1063.             try:
  1064.                 self.DeviceListRefresh()
  1065.             finally:
  1066.                 self.deviceRefreshAll.setEnabled(True)
  1067.  
  1068.  
  1069.     def callback(self):
  1070.         qApp.processEvents()
  1071.  
  1072.  
  1073.     # ***********************************************************************************
  1074.     #
  1075.     # DEVICE LIST RIGHT CLICK
  1076.     #
  1077.     # ***********************************************************************************
  1078.  
  1079.     def DeviceList_rightButtonClicked(self, item, pos):
  1080.         popup = QPopupMenu(self)
  1081.  
  1082.         if item is not None and item is self.DeviceList.currentItem():
  1083.             if self.cur_device.error_state != ERROR_STATE_ERROR:
  1084.                 if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
  1085.                     popup.insertItem(self.__tr("Print..."), self.PrintButton_clicked)
  1086.  
  1087.                     if self.cur_device.scan_type:
  1088.                         popup.insertItem(self.__tr("Scan..."), self.ScanButton_clicked)
  1089.  
  1090.                     if self.cur_device.pcard_type:
  1091.                         popup.insertItem(self.__tr("Access Photo Cards..."), self.PCardButton_clicked)
  1092.  
  1093.                     if self.cur_device.copy_type:
  1094.                         popup.insertItem(self.__tr("Make Copies..."), self.MakeCopiesButton_clicked)
  1095.  
  1096.                 elif self.cur_device.device_type == DEVICE_TYPE_FAX:
  1097.                     if self.cur_device.fax_type:
  1098.                         popup.insertItem(self.__tr("Send Fax..."), self.SendFaxButton_clicked)
  1099.  
  1100.                 popup.insertSeparator()
  1101.  
  1102.                 if self.cur_device.device_settings_ui is not None:
  1103.                     popup.insertItem(self.__tr("Device Settings..."), self.deviceSettingsButton_clicked)
  1104.  
  1105.             if not self.rescanning:
  1106.                 popup.insertItem(self.__tr("Refresh Device"), self.deviceRescanAction_activated)
  1107.  
  1108.         if not self.rescanning:
  1109.             popup.insertItem(self.__tr("Refresh All"), self.deviceRefreshAll_activated)
  1110.  
  1111.         popup.popup(pos)            
  1112.  
  1113.  
  1114.     # ***********************************************************************************
  1115.     #
  1116.     # PRINTER NAME COMBOS
  1117.     #
  1118.     # ***********************************************************************************
  1119.  
  1120.     def updatePrinterList(self):
  1121.         if self.cur_device is not None and \
  1122.             self.cur_device.supported:
  1123.  
  1124.             printers = cups.getPrinters()
  1125.             self.cur_device.cups_printers = []
  1126.  
  1127.             for p in printers:
  1128.                 if p.device_uri == self.cur_device_uri:
  1129.                     self.cur_device.cups_printers.append(p.name)
  1130.  
  1131.  
  1132.     def UpdatePrinterCombos(self):
  1133.         self.PrintSettingsPrinterCombo.clear()
  1134.         self.PrintJobPrinterCombo.clear()
  1135.  
  1136.         if self.cur_device is not None and \
  1137.             self.cur_device.supported:
  1138.  
  1139.             for c in self.cur_device.cups_printers:
  1140.                 self.PrintSettingsPrinterCombo.insertItem(c.decode("utf-8"))
  1141.                 self.PrintJobPrinterCombo.insertItem(c.decode("utf-8"))
  1142.  
  1143.             self.cur_printer = unicode(self.PrintSettingsPrinterCombo.currentText())
  1144.  
  1145.     def PrintSettingsPrinterCombo_activated(self, s):
  1146.         self.cur_printer = unicode(s)
  1147.         self.PrintJobPrinterCombo.setCurrentText(self.cur_printer.encode("latin1")) # TODO: ?
  1148.         return self.PrinterCombo_activated(self.cur_printer)
  1149.  
  1150.     def PrintJobPrinterCombo_activated(self, s):
  1151.         self.cur_printer = unicode(s) 
  1152.         self.PrintSettingsPrinterCombo.setCurrentText(self.cur_printer.encode("latin1")) # TODO: ?
  1153.         return self.PrinterCombo_activated(self.cur_printer)
  1154.  
  1155.     def PrinterCombo_activated(self, printer):
  1156.         self.TabIndex[self.Tabs.currentPage()]()
  1157.         self.UpdatePrintSettingsTabPrinter()
  1158.  
  1159.  
  1160.  
  1161.     # ***********************************************************************************
  1162.     #
  1163.     # FUNCTIONS/ACTION TAB
  1164.     #
  1165.     # ***********************************************************************************    
  1166.  
  1167.     def InitFuncsTab(self):
  1168.         self.click_lock = None
  1169.  
  1170.     def UpdateFuncsTab(self):
  1171.         self.iconList.clear()
  1172.  
  1173.         d = self.cur_device
  1174.         
  1175.         if d is not None:
  1176.         
  1177.             avail = d.device_state != DEVICE_STATE_NOT_FOUND and d.supported
  1178.             fax = d.fax_type and prop.fax_build and d.device_type == DEVICE_TYPE_FAX and \
  1179.                 sys.hexversion >= 0x020300f0 and avail
  1180.             printer = d.device_type == DEVICE_TYPE_PRINTER and avail
  1181.             req_plugin = d.plugin == PLUGIN_REQUIRED
  1182.             opt_plugin = d.plugin == PLUGIN_OPTIONAL
  1183.             
  1184.             hplip_conf = ConfigParser.ConfigParser()
  1185.             fp = open("/etc/hp/hplip.conf", "r")
  1186.             hplip_conf.readfp(fp)
  1187.             fp.close()
  1188.             
  1189.             try:
  1190.                 plugin_installed = utils.to_bool(hplip_conf.get("hplip", "plugin"))
  1191.             except ConfigParser.NoOptionError:
  1192.                 plugin_installed = False
  1193.             
  1194.             if d.plugin:
  1195.                 if req_plugin and plugin_installed:
  1196.                     x = self.__tr("Download and install<br>required plugin (already installed).")
  1197.                 
  1198.                 elif req_plugin and not plugin_installed:
  1199.                     x = self.__tr("Download and install<br>required plugin (needs installation).")
  1200.                 
  1201.                 elif opt_plugin and plugin_installed:
  1202.                     x = self.__tr("Download and install<br>optional plugin (already installed).")
  1203.                 
  1204.                 elif opt_plugin and not plugin_installed:
  1205.                     x = self.__tr("Download and install<br>optional plugin (needs installation).")
  1206.             
  1207.             else:
  1208.                 x = ''
  1209.  
  1210.             
  1211.             self.ICONS = [ 
  1212.                 
  1213.                 # PRINTER
  1214.                 
  1215.                 (lambda : printer,                 # filter func
  1216.                 self.__tr("Print"),                      # Text
  1217.                 "print",       # Icon
  1218.                 self.__tr("Print documents or files."),  # Tooltip
  1219.                 self.user_settings.cmd_print),           # command/action
  1220.  
  1221.                 (lambda : d.scan_type and prop.scan_build and \
  1222.                     d.device_type == DEVICE_TYPE_PRINTER and avail, 
  1223.                 self.__tr("Scan"),
  1224.                 "scan", 
  1225.                 self.__tr("Scan a document, image, or photograph.<br>"), 
  1226.                 self.user_settings.cmd_scan),
  1227.  
  1228.                 (lambda : d.copy_type and d.device_type == DEVICE_TYPE_PRINTER and avail, 
  1229.                 self.__tr("Make Copies"), 
  1230.                 "makecopies", 
  1231.                 self.__tr("Make copies on the device controlled by the PC.<br>"), 
  1232.                 self.user_settings.cmd_copy),
  1233.  
  1234.                 (lambda : d.pcard_type and d.device_type == DEVICE_TYPE_PRINTER and avail,
  1235.                 self.__tr("Unload Photo Card"),
  1236.                 "makecopies",
  1237.                 self.__tr("Copy images from the device's photo card to the PC."),
  1238.                 self.user_settings.cmd_pcard),
  1239.  
  1240.                 # FAX
  1241.  
  1242.                 (lambda: fax,
  1243.                 self.__tr("Send Fax"),
  1244.                 "fax",
  1245.                 self.__tr("Send a fax from the PC."),
  1246.                 self.user_settings.cmd_fax),
  1247.  
  1248.                 (lambda: fax,
  1249.                 self.__tr("Fax Setup"),
  1250.                 "fax_setup",
  1251.                 self.__tr("Fax support must be setup before you can send faxes."),
  1252.                 self.faxSettingsButton_clicked),
  1253.  
  1254.                 (lambda: fax,
  1255.                 self.__tr("Fax Address Book"),
  1256.                 "fab",
  1257.                 self.__tr("Setup fax phone numbers to use when sending faxes from the PC."),
  1258.                 self.cmd_fab),
  1259.  
  1260.                 # SETTINGS/TOOLS
  1261.  
  1262.                 (lambda : self.cur_device.device_settings_ui is not None and avail,
  1263.                 self.__tr("Device Settings"),
  1264.                 "settings",
  1265.                 self.__tr("Your device has special device settings.<br>You may alter these settings here."), 
  1266.                 self.deviceSettingsButton_clicked),
  1267.  
  1268.                 (lambda : printer,
  1269.                 self.__tr("Print Test Page"),
  1270.                 "testpage",
  1271.                 self.__tr("Print a test page to test the setup of your printer."),
  1272.                 self.PrintTestPageButton_clicked),
  1273.  
  1274.                 (lambda : True,
  1275.                 self.__tr("View Printer (Queue) Information"),
  1276.                 "cups",
  1277.                 self.__tr("View the printers (queues) installed in CUPS."), 
  1278.                 self.viewPrinterInformation),
  1279.  
  1280.                 (lambda : True,
  1281.                 self.__tr("View Device Information"),
  1282.                 "info",
  1283.                 self.__tr("This information is primarily useful for <br>debugging and troubleshooting (advanced)."),
  1284.                 self.viewInformation),
  1285.  
  1286.                 (lambda: printer and d.align_type,
  1287.                 self.__tr("Align Cartridges (Print Heads)"), 
  1288.                 "align",
  1289.                 self.__tr("This will improve the quality of output when a new cartridge is installed."), 
  1290.                 self.AlignPensButton_clicked),
  1291.  
  1292.                 (lambda: printer and d.clean_type,
  1293.                 self.__tr("Clean Cartridges"),
  1294.                 "clean",
  1295.                 self.__tr("You only need to perform this action if you are<br>having problems with poor printout quality due to clogged ink nozzles."), 
  1296.                 self.CleanPensButton_clicked),
  1297.  
  1298.                 (lambda: printer and d.color_cal_type and d.color_cal_type == COLOR_CAL_TYPE_TYPHOON,
  1299.                 self.__tr("Color Calibration"),
  1300.                 "colorcal",
  1301.                 self.__tr("Use this procedure to optimimize your printer's color output<br>(requires glossy photo paper)."),  
  1302.                 self.ColorCalibrationButton_clicked),
  1303.  
  1304.                 (lambda: printer and d.color_cal_type and d.color_cal_type != COLOR_CAL_TYPE_TYPHOON,
  1305.                 self.__tr("Color Calibration"),
  1306.                 "colorcal",
  1307.                 self.__tr("Use this procedure to optimimize your printer's color output."), 
  1308.                 self.ColorCalibrationButton_clicked),
  1309.  
  1310.                 (lambda: printer and d.linefeed_cal_type,
  1311.                 self.__tr("Line Feed Calibration"), 
  1312.                 "linefeed_cal",
  1313.                 self.__tr("Use line feed calibration to optimize print quality<br>(to remove gaps in the printed output)."),
  1314.                 self.linefeedCalibration),
  1315.  
  1316.                 (lambda: printer and d.pq_diag_type,
  1317.                 self.__tr("Print Diagnostic Page"), 
  1318.                 "pq_diag",
  1319.                 self.__tr("Your printer can print a test page <br>to help diagnose print quality problems."),
  1320.                 self.pqDiag),
  1321.  
  1322.                 # FIRMWARE
  1323.                 
  1324.                 (lambda : printer and d.fw_download,
  1325.                 self.__tr("Download Firmware"),
  1326.                 "firmware",
  1327.                 self.__tr("Download firmware to your printer <br>(required on some devices after each power-up)."), 
  1328.                 self.downloadFirmware),
  1329.  
  1330.                 # PLUGIN
  1331.                 
  1332.                 (lambda : req_plugin,
  1333.                 self.__tr("Install Required Plugin"),
  1334.                 "plugin",
  1335.                 x, #self.__tr("Download and install the HPLIP plugin."), 
  1336.                 self.downloadPlugin),
  1337.                 
  1338.                 (lambda : opt_plugin,
  1339.                 self.__tr("Install Optional Plugin"),
  1340.                 "plugin",
  1341.                 x, #self.__tr("Download and install the HPLIP plugin."), 
  1342.                 self.downloadPlugin),
  1343.                 
  1344.                 # HELP/WEBSITE
  1345.                 
  1346.                 (lambda : True,
  1347.                 self.__tr("Visit HPLIP Website"),
  1348.                 "support2",
  1349.                 self.__tr("Visit HPLIP website."),  
  1350.                 self.viewSupport),
  1351.  
  1352.                 (lambda : True,
  1353.                 self.__tr("Help"),
  1354.                 "help",
  1355.                 self.__tr("View HPLIP help."),  
  1356.                 self.viewHelp),
  1357.  
  1358.             ]
  1359.  
  1360.             if not self.func_icons_cached:
  1361.                 for filter, text, icon, tooltip, cmd in self.ICONS:
  1362.                     self.func_icons[icon] = load_pixmap(icon, '32x32')
  1363.                 self.func_icons_cached = True
  1364.  
  1365.  
  1366.  
  1367.             for filter, text, icon, tooltip, cmd in self.ICONS:
  1368.                 if filter is not None:
  1369.                     if not filter(): 
  1370.                         continue
  1371.  
  1372.                 FuncViewItem(self.iconList, text, 
  1373.                     self.func_icons[icon], 
  1374.                     tooltip, 
  1375.                     cmd)
  1376.  
  1377.  
  1378.     def downloadPlugin(self):
  1379.         su_sudo = None
  1380.  
  1381.         if utils.which('kdesu'):
  1382.             su_sudo = 'kdesu -- %s'
  1383.  
  1384.         elif utils.which('kdesudo'):
  1385.             su_sudo = 'kdesudo -- %s'
  1386.  
  1387.         elif utils.which('gnomesu'):
  1388.             su_sudo = 'gnomesu -c "%s"'
  1389.         
  1390.         elif utils.which('gksu'):
  1391.             su_sudo = 'gksu "%s"'
  1392.  
  1393.         if su_sudo is None:
  1394.             QMessageBox.critical(self,
  1395.                 self.caption(),
  1396.                 self.__tr("<b>Unable to find an appropriate su/sudo utility to run hp-plugin.</b>"),
  1397.                 QMessageBox.Ok,
  1398.                 QMessageBox.NoButton,
  1399.                 QMessageBox.NoButton)
  1400.  
  1401.         else:
  1402.             if utils.which('hp-plugin'):
  1403.                 cmd = su_sudo % 'hp-plugin -u'
  1404.             else:
  1405.                 cmd = su_sudo % 'python ./plugin.py -u'
  1406.  
  1407.             log.debug(cmd)
  1408.             utils.run(cmd, log_output=True, password_func=None, timeout=1)
  1409.             #print os.system(cmd)
  1410.             
  1411.             self.UpdateFuncsTab()
  1412.             
  1413.     
  1414.     def iconList_clicked(self, item):
  1415.         return self.RunFuncCmd(item)
  1416.  
  1417.  
  1418.     def RunFuncCmd(self, item):
  1419.         if item is not None and self.click_lock is not item:
  1420.             try:
  1421.                 item.cmd()
  1422.             except TypeError:
  1423.                 self.RunCommand(item.cmd)
  1424.  
  1425.             self.click_lock = item
  1426.             QTimer.singleShot(1000, self.UnlockClick)
  1427.  
  1428.  
  1429.     def UnlockClick(self):
  1430.         self.click_lock = None
  1431.  
  1432.  
  1433.     def RunFuncCmdContext(self):
  1434.         return self.RunFuncCmd(self.iconList.currentItem())
  1435.  
  1436.  
  1437.     def iconList_contextMenuRequested(self, item, pos):
  1438.         if item is not None and item is self.iconList.currentItem():
  1439.             popup = QPopupMenu(self)
  1440.             popup.insertItem(self.__tr("Open..."), self.RunFuncCmdContext)
  1441.             popup.popup(pos)            
  1442.  
  1443.  
  1444.     def iconList_returnPressed(self, item):
  1445.         return self.RunFuncCmd(item)
  1446.  
  1447.  
  1448.     def deviceSettingsButton_clicked(self):
  1449.         try:
  1450.             self.cur_device.open()
  1451.             self.cur_device.device_settings_ui(self.cur_device, self)
  1452.         finally:
  1453.             self.cur_device.close()
  1454.  
  1455.  
  1456.     def setupDevice_activated(self):
  1457.         try:
  1458.             self.cur_device.open()
  1459.             self.cur_device.device_settings_ui(self.cur_device, self)
  1460.         finally:
  1461.             self.cur_device.close()
  1462.  
  1463.  
  1464.     def PrintButton_clicked(self):
  1465.         self.RunCommand(self.user_settings.cmd_print)
  1466.  
  1467.  
  1468.     def ScanButton_clicked(self):
  1469.         self.RunCommand(self.user_settings.cmd_scan)
  1470.  
  1471.  
  1472.     def PCardButton_clicked(self):
  1473.         if self.cur_device.pcard_type == PCARD_TYPE_MLC:
  1474.             self.RunCommand(self.user_settings.cmd_pcard)
  1475.  
  1476.         elif self.cur_device.pcard_type == PCARD_TYPE_USB_MASS_STORAGE:
  1477.             self.FailureUI(self.__tr("<p><b>Photocards on your printer are only available by mounting them as drives using USB mass storage.</b><p>Please refer to your distribution's documentation for setup and usage instructions."))
  1478.  
  1479.  
  1480.     def SendFaxButton_clicked(self):
  1481.         self.RunCommand(self.user_settings.cmd_fax)
  1482.  
  1483.  
  1484.     def MakeCopiesButton_clicked(self):
  1485.         self.RunCommand(self.user_settings.cmd_copy)
  1486.  
  1487.  
  1488.     def ConfigureFeaturesButton_clicked(self):
  1489.         self.settingsConfigure_activated(2)
  1490.  
  1491.  
  1492.     def viewInformation(self):
  1493.         dlg = ScrollDialog(ScrollDeviceInfoView, self.cur_device, self.cur_printer, self.service, self)
  1494.         dlg.exec_loop()
  1495.  
  1496.  
  1497.     def viewPrinterInformation(self):
  1498.         dlg = ScrollDialog(ScrollPrinterInfoView, self.cur_device, self.cur_printer, self.service, self)
  1499.         dlg.exec_loop()
  1500.  
  1501.  
  1502.     def viewHelp(self):
  1503.         f = "http://hplip.sf.net"
  1504.  
  1505.         if prop.doc_build:
  1506.             g = os.path.join(sys_cfg.dirs.doc, 'index.html')
  1507.             if os.path.exists(g):
  1508.                 f = "file://%s" % g
  1509.  
  1510.         log.debug(f)
  1511.         utils.openURL(f)
  1512.  
  1513.         
  1514.     def viewSupport(self):
  1515.         f = "http://hplip.sf.net"
  1516.         log.debug(f)
  1517.         utils.openURL(f)
  1518.         
  1519.  
  1520.     def pqDiag(self):
  1521.         d = self.cur_device
  1522.         pq_diag = d.pq_diag_type
  1523.  
  1524.         try:
  1525.             QApplication.setOverrideCursor(QApplication.waitCursor)
  1526.  
  1527.             try:
  1528.                 d.open()
  1529.             except Error:
  1530.                 self.CheckDeviceUI()
  1531.             else:
  1532.                 if d.isIdleAndNoError():
  1533.                     QApplication.restoreOverrideCursor()
  1534.  
  1535.                     if pq_diag == 1:
  1536.                         maint.printQualityDiagType1(d, self.LoadPaperUI)
  1537.  
  1538.                     elif pq_diag == 2:
  1539.                         maint.printQualityDiagType2(d, self.LoadPaperUI)
  1540.  
  1541.                 else:
  1542.                     self.CheckDeviceUI()
  1543.  
  1544.         finally:
  1545.             d.close()
  1546.             QApplication.restoreOverrideCursor()
  1547.  
  1548.  
  1549.     def linefeedCalibration(self):
  1550.         d = self.cur_device
  1551.         linefeed_type = d.linefeed_cal_type
  1552.  
  1553.         try:    
  1554.             QApplication.setOverrideCursor(QApplication.waitCursor)
  1555.  
  1556.             try:
  1557.                 d.open()
  1558.             except Error:
  1559.                 self.CheckDeviceUI()
  1560.             else:
  1561.                 if d.isIdleAndNoError():
  1562.                     QApplication.restoreOverrideCursor()
  1563.  
  1564.                     if linefeed_type == 1:
  1565.                         maint.linefeedCalType1(d, self.LoadPaperUI)
  1566.  
  1567.                     elif linefeed_type == 2:
  1568.                         maint.linefeedCalType2(d, self.LoadPaperUI)
  1569.  
  1570.                 else:
  1571.                     self.CheckDeviceUI()
  1572.  
  1573.         finally:
  1574.             d.close()
  1575.             QApplication.restoreOverrideCursor()
  1576.  
  1577.  
  1578.     def downloadFirmware(self):
  1579.         d = self.cur_device
  1580.         ok = False
  1581.         
  1582.         try:
  1583.             QApplication.setOverrideCursor(QApplication.waitCursor)
  1584.             d.open()
  1585.  
  1586.             if d.isIdleAndNoError():
  1587.                 ok = d.downloadFirmware()
  1588.             
  1589.         finally:
  1590.             d.close()
  1591.             QApplication.restoreOverrideCursor()
  1592.         
  1593.             if not ok:
  1594.                 self.FailureUI(self.__tr("<b>An error occured downloading firmware file.</b><p>Please check your printer and ensure that the HPLIP plugin has been installed."))
  1595.  
  1596.  
  1597.     def CheckDeviceUI(self):
  1598.         self.FailureUI(self.__tr("<b>Device is busy or in an error state.</b><p>Please check device and try again."))
  1599.  
  1600.  
  1601.     def LoadPaperUI(self):
  1602.         if LoadPaperForm(self).exec_loop() == QDialog.Accepted:
  1603.             return True
  1604.         return False
  1605.  
  1606.  
  1607.     def AlignmentNumberUI(self, letter, hortvert, colors, line_count, choice_count):
  1608.         dlg = AlignForm(self, letter, hortvert, colors, line_count, choice_count)
  1609.         if dlg.exec_loop() == QDialog.Accepted:
  1610.             return True, dlg.value
  1611.         else:
  1612.             return False, 0
  1613.  
  1614.  
  1615.     def PaperEdgeUI(self, maximum):
  1616.         dlg = PaperEdgeAlignForm(self)
  1617.         if dlg.exec_loop() == QDialog.Accepted:
  1618.             return True, dlg.value
  1619.         else:
  1620.             return False, 0
  1621.  
  1622.  
  1623.     def BothPensRequiredUI(self):
  1624.         self.WarningUI(self.__tr("<p><b>Both cartridges are required for alignment.</b><p>Please install both cartridges and try again."))
  1625.  
  1626.  
  1627.     def InvalidPenUI(self):
  1628.         self.WarningUI(self.__tr("<p><b>One or more cartiridges are missing from the printer.</b><p>Please install cartridge(s) and try again."))
  1629.  
  1630.  
  1631.     def PhotoPenRequiredUI(self):
  1632.         self.WarningUI(self.__tr("<p><b>Both the photo and color cartridges must be inserted into the printer to perform color calibration.</b><p>If you are planning on printing with the photo cartridge, please insert it and try again."))
  1633.  
  1634.  
  1635.     def PhotoPenRequiredUI2(self):
  1636.         self.WarningUI(self.__tr("<p><b>Both the photo (regular photo or photo blue) and color cartridges must be inserted into the printer to perform color calibration.</b><p>If you are planning on printing with the photo or photo blue cartridge, please insert it and try again."))
  1637.  
  1638.  
  1639.     def NotPhotoOnlyRequired(self): # Type 11
  1640.         self.WarningUI(self.__tr("<p><b>Cannot align with only the photo cartridge installed.</b><p>Please install other cartridges and try again."))
  1641.  
  1642.  
  1643.     def AioUI1(self):
  1644.         dlg = AlignType6Form1(self)
  1645.         return dlg.exec_loop() == QDialog.Accepted
  1646.  
  1647.  
  1648.     def AioUI2(self):
  1649.         AlignType6Form2(self).exec_loop()
  1650.  
  1651.  
  1652.     def Align10and11UI(self, pattern, align_type):
  1653.         dlg = Align10Form(pattern, align_type, self)
  1654.         dlg.exec_loop()
  1655.         return dlg.getValues()
  1656.  
  1657.  
  1658.     def AlignPensButton_clicked(self):
  1659.         d = self.cur_device
  1660.         align_type = d.align_type
  1661.  
  1662.         log.debug("Align: %s %s (type=%d) %s" % ("*"*20, self.cur_device.device_uri, align_type, "*"*20))
  1663.  
  1664.         try:
  1665.             QApplication.setOverrideCursor(QApplication.waitCursor)
  1666.  
  1667.             try:
  1668.                 d.open()
  1669.             except Error:
  1670.                 self.CheckDeviceUI()
  1671.             else:
  1672.                 if d.isIdleAndNoError():
  1673.                     QApplication.restoreOverrideCursor()
  1674.  
  1675.                     if align_type == ALIGN_TYPE_AUTO:
  1676.                         maint.AlignType1(d, self.LoadPaperUI)
  1677.  
  1678.                     elif align_type == ALIGN_TYPE_8XX:
  1679.                         maint.AlignType2(d, self.LoadPaperUI, self.AlignmentNumberUI,
  1680.                self.BothPensRequiredUI)
  1681.  
  1682.                     elif align_type in (ALIGN_TYPE_9XX,ALIGN_TYPE_9XX_NO_EDGE_ALIGN):
  1683.                          maint.AlignType3(d, self.LoadPaperUI, self.AlignmentNumberUI,
  1684.                 self.PaperEdgeUI, align_type)
  1685.  
  1686.                     elif align_type in (ALIGN_TYPE_LIDIL_0_3_8, ALIGN_TYPE_LIDIL_0_4_3, ALIGN_TYPE_LIDIL_VIP):
  1687.                         maint.AlignxBow(d, align_type, self.LoadPaperUI, self.AlignmentNumberUI,
  1688.               self.PaperEdgeUI, self.InvalidPenUI, self.ColorAdjUI)
  1689.  
  1690.                     elif align_type == ALIGN_TYPE_LIDIL_AIO:
  1691.                         maint.AlignType6(d, self.AioUI1, self.AioUI2, self.LoadPaperUI)
  1692.  
  1693.                     elif align_type == ALIGN_TYPE_DESKJET_450:
  1694.                         maint.AlignType8(d, self.LoadPaperUI, self.AlignmentNumberUI)
  1695.  
  1696.                     elif align_type == ALIGN_TYPE_LBOW:
  1697.                         maint.AlignType10(d, self.LoadPaperUI, self.Align10and11UI) 
  1698.  
  1699.                     elif align_type == ALIGN_TYPE_LIDIL_0_5_4:
  1700.                         maint.AlignType11(d, self.LoadPaperUI, self.Align10and11UI, self.NotPhotoOnlyRequired) 
  1701.  
  1702.                     elif align_type == ALIGN_TYPE_OJ_PRO:
  1703.                         maint.AlignType12(d, self.LoadPaperUI)
  1704.  
  1705.                 else:
  1706.                     self.CheckDeviceUI()
  1707.  
  1708.         finally:
  1709.             d.close()
  1710.             QApplication.restoreOverrideCursor()
  1711.  
  1712.  
  1713.     def ColorAdjUI(self, line, maximum=0):
  1714.         dlg = ColorAdjForm(self, line)
  1715.         if dlg.exec_loop() == QDialog.Accepted:
  1716.             return True, dlg.value
  1717.         else:
  1718.             return False, 0
  1719.  
  1720.  
  1721.     def ColorCalUI(self):
  1722.         dlg = ColorCalForm(self)
  1723.         if dlg.exec_loop() == QDialog.Accepted:
  1724.             return True, dlg.value
  1725.         else:
  1726.             return False, 0
  1727.  
  1728.  
  1729.     def ColorCalUI2(self):
  1730.         dlg = ColorCalForm2(self)
  1731.         if dlg.exec_loop() == QDialog.Accepted:
  1732.             return True, dlg.value
  1733.         else:
  1734.             return False, 0
  1735.  
  1736.  
  1737.     def ColorCalUI4(self):
  1738.         dlg = ColorCal4Form(self)
  1739.         if dlg.exec_loop() == QDialog.Accepted:
  1740.             return True, dlg.values
  1741.         else:
  1742.             return False, None
  1743.  
  1744.  
  1745.     def ColorCalibrationButton_clicked(self):
  1746.         d = self.cur_device
  1747.         color_cal_type = d.color_cal_type
  1748.         log.debug("Color-cal: %s %s (type=%d) %s" % ("*"*20, self.cur_device.device_uri, color_cal_type, "*"*20))
  1749.  
  1750.         if color_cal_type == COLOR_CAL_TYPE_TYPHOON:
  1751.             dlg = ScrollDialog(ScrollColorCalView, self.cur_device, self.cur_printer, self.service, self)
  1752.             dlg.exec_loop()
  1753.         else:
  1754.             try:
  1755.                 QApplication.setOverrideCursor(QApplication.waitCursor)
  1756.  
  1757.                 try:
  1758.                     d.open()
  1759.                 except Error:
  1760.                     self.CheckDeviceUI()
  1761.                 else:
  1762.                     if d.isIdleAndNoError():
  1763.                         QApplication.restoreOverrideCursor()
  1764.  
  1765.                         if color_cal_type == COLOR_CAL_TYPE_DESKJET_450:
  1766.                             maint.colorCalType1(d, self.LoadPaperUI, self.ColorCalUI,
  1767.                                 self.PhotoPenRequiredUI)
  1768.  
  1769.                         elif color_cal_type == COLOR_CAL_TYPE_MALIBU_CRICK:
  1770.                             maint.colorCalType2(d, self.LoadPaperUI, self.ColorCalUI2,
  1771.                                 self.InvalidPenUI)
  1772.  
  1773.                         elif color_cal_type == COLOR_CAL_TYPE_STRINGRAY_LONGBOW_TORNADO:
  1774.                             maint.colorCalType3(d, self.LoadPaperUI, self.ColorAdjUI,
  1775.                                 self.PhotoPenRequiredUI2)
  1776.  
  1777.                         elif color_cal_type == COLOR_CAL_TYPE_CONNERY:
  1778.                             maint.colorCalType4(d, self.LoadPaperUI, self.ColorCalUI4,
  1779.                                 self.WaitUI)
  1780.  
  1781.                         elif color_cal_type == COLOR_CAL_TYPE_COUSTEAU:
  1782.                             maint.colorCalType5(d, self.LoadPaperUI)
  1783.  
  1784.                         elif color_cal_type == COLOR_CAL_TYPE_CARRIER:
  1785.                             maint.colorCalType6(d, self.LoadPaperUI)
  1786.  
  1787.                     else:
  1788.                         self.CheckDeviceUI()
  1789.  
  1790.             finally:
  1791.                 d.close()
  1792.                 QApplication.restoreOverrideCursor()
  1793.  
  1794.  
  1795.     def PrintTestPageButton_clicked(self):
  1796.         dlg = ScrollDialog(ScrollTestpageView, self.cur_device, self.cur_printer, self.service, self)        
  1797.         dlg.exec_loop()
  1798.  
  1799.  
  1800.     def CleanUI1(self):
  1801.         return CleaningForm(self, self.cur_device, 1).exec_loop() == QDialog.Accepted
  1802.  
  1803.  
  1804.     def CleanUI2(self):
  1805.         return CleaningForm(self, self.cur_device, 2).exec_loop() == QDialog.Accepted
  1806.  
  1807.  
  1808.     def CleanUI3(self):
  1809.         CleaningForm2(self).exec_loop()
  1810.         return True
  1811.  
  1812.  
  1813.     def WaitUI(self, seconds):
  1814.         WaitForm(seconds, None, self).exec_loop()
  1815.  
  1816.  
  1817.     def CleanPensButton_clicked(self):
  1818.         d = self.cur_device
  1819.         clean_type = d.clean_type
  1820.         log.debug("Clean: %s %s (type=%d) %s" % ("*"*20, self.cur_device.device_uri, clean_type, "*"*20))
  1821.  
  1822.         try:
  1823.             QApplication.setOverrideCursor(QApplication.waitCursor)
  1824.  
  1825.             try:
  1826.                 d.open()
  1827.             except Error:
  1828.                 self.CheckDeviceUI()
  1829.             else:
  1830.                 if d.isIdleAndNoError():
  1831.                     QApplication.restoreOverrideCursor()
  1832.  
  1833.                     if clean_type == CLEAN_TYPE_PCL:
  1834.                         maint.cleaning(d, clean_type, maint.cleanType1, maint.primeType1,
  1835.                             maint.wipeAndSpitType1, self.LoadPaperUI,
  1836.                             self.CleanUI1, self.CleanUI2, self.CleanUI3,
  1837.                             self.WaitUI)
  1838.  
  1839.                     elif clean_type == CLEAN_TYPE_LIDIL:
  1840.                         maint.cleaning(d, clean_type, maint.cleanType2, maint.primeType2,
  1841.                             maint.wipeAndSpitType2, self.LoadPaperUI,
  1842.                             self.CleanUI1, self.CleanUI2, self.CleanUI3,
  1843.                             self.WaitUI)
  1844.  
  1845.                     elif clean_type == CLEAN_TYPE_PCL_WITH_PRINTOUT:
  1846.                         maint.cleaning(d, clean_type, maint.cleanType1, maint.primeType1,
  1847.                             maint.wipeAndSpitType1, self.LoadPaperUI,
  1848.                             self.CleanUI1, self.CleanUI2, self.CleanUI3,
  1849.                             self.WaitUI)
  1850.                 else:
  1851.                     self.CheckDeviceUI()
  1852.  
  1853.         finally:
  1854.             d.close()
  1855.             QApplication.restoreOverrideCursor()
  1856.  
  1857.  
  1858.     def OpenEmbeddedBrowserButton_clicked(self):
  1859.         utils.openURL("http://%s" % self.cur_device.host)
  1860.  
  1861.  
  1862.     def faxAddressBookButton_clicked(self):
  1863.         self.RunCommand(self.cmd_fab)
  1864.  
  1865.  
  1866.     def faxSettingsButton_clicked(self):
  1867.         try:
  1868.             try:
  1869.                 self.cur_device.open()
  1870.             except Error:
  1871.                 self.CheckDeviceUI()
  1872.             else:
  1873.                 try:
  1874.                     result_code, fax_num = self.cur_device.getPML(pml.OID_FAX_LOCAL_PHONE_NUM)
  1875.                 except Error:
  1876.                     log.error("PML failure.")
  1877.                     self.FailureUI(self.__tr("<p><b>Operation failed. Device busy.</b>"))
  1878.                     return
  1879.  
  1880.                 fax_num = str(fax_num)
  1881.  
  1882.                 try:
  1883.                     result_code, name = self.cur_device.getPML(pml.OID_FAX_STATION_NAME)
  1884.                 except Error:
  1885.                     log.error("PML failure.")
  1886.                     self.FailureUI(self.__tr("<p><b>Operation failed. Device busy.</b>"))
  1887.                     return
  1888.  
  1889.                 name = str(name)
  1890.  
  1891.                 dlg = FaxSettingsForm(self.cur_device, fax_num, name, self)
  1892.                 dlg.exec_loop()
  1893.  
  1894.         finally:
  1895.             self.cur_device.close()
  1896.  
  1897.  
  1898.     def addressBookButton_clicked(self):
  1899.         self.RunCommand(self.cmd_fab)
  1900.  
  1901.  
  1902.  
  1903.     # ***********************************************************************************
  1904.     #
  1905.     # STATUS TAB
  1906.     #
  1907.     # ***********************************************************************************      
  1908.  
  1909.     def InitStatusTab(self):
  1910.         self.statusListView.setSorting(-1)
  1911.         self.statusListView.setColumnText(0, QString(""))
  1912.         #self.statusListView.setColumnWidthMode(0, QListView.Manual)
  1913.         self.statusListView.setColumnWidth(0, 16)
  1914.  
  1915.  
  1916.     def UpdateStatusTab(self):
  1917.         #log.debug("UpdateStatusTab()")
  1918.         self.UpdateHistory()
  1919.         self.UpdatePanel()
  1920.         self.UpdateStatusList()
  1921.  
  1922.  
  1923.     def UpdatePanel(self):
  1924.         if self.cur_device is not None and \
  1925.             self.cur_device.hist and \
  1926.             self.cur_device.supported:
  1927.  
  1928.             dq = self.cur_device.dq
  1929.  
  1930.             if dq.get('panel', 0) == 1:
  1931.                 line1 = dq.get('panel-line1', '')
  1932.                 line2 = dq.get('panel-line2', '')
  1933.             else:
  1934.                 try:
  1935.                     line1 = device.queryString(self.cur_device.hist[0].event_code)
  1936.                 except (AttributeError, TypeError):
  1937.                     line1 = ''
  1938.                     
  1939.                 line2 = ''
  1940.  
  1941.             pm = load_pixmap('panel_lcd', 'other')
  1942.  
  1943.             p = QPainter()
  1944.             p.begin(pm)
  1945.             p.setPen(QColor(0, 0, 0))
  1946.             p.setFont(self.font())
  1947.  
  1948.             x, y_line1, y_line2 = 10, 17, 33
  1949.  
  1950.             # TODO: Scroll long lines
  1951.             p.drawText(x, y_line1, line1)
  1952.             p.drawText(x, y_line2, line2)
  1953.             p.end()
  1954.  
  1955.             self.panel.setPixmap(pm)
  1956.  
  1957.         else:
  1958.             self.panel.setPixmap(load_pixmap('panel_lcd', 'other'))
  1959.  
  1960.  
  1961.     def UpdateHistory(self, dev=None):
  1962.         if self.dbus_avail:
  1963.             if dev is None:
  1964.                 dev = self.cur_device
  1965.  
  1966.             return dev.queryHistory()
  1967.  
  1968.         self.cur_device.hist = [self.cur_device.last_event]
  1969.  
  1970.  
  1971.  
  1972.     def UpdateStatusList(self):
  1973.         self.statusListView.clear()
  1974.         row = 0
  1975.         hist = self.cur_device.hist[:]
  1976.         
  1977.         if hist:
  1978.             hist.reverse()
  1979.             row = len(hist)-1
  1980.  
  1981.             for e in hist:
  1982.                 if e is None:
  1983.                     continue
  1984.                     
  1985.                 ess = device.queryString(e.event_code, 0)
  1986.                 esl = device.queryString(e.event_code, 1)
  1987.  
  1988.                 if row == 0:
  1989.                     desc = self.__tr("(most recent)")
  1990.  
  1991.                 else:
  1992.                     desc = self.getTimeDeltaDesc(e.timedate)
  1993.  
  1994.                 dt = QDateTime()
  1995.                 dt.setTime_t(int(e.timedate), Qt.LocalTime)
  1996.  
  1997.                 # TODO: In Qt4.x, use QLocale.toString(date, format)
  1998.                 tt = QString("%1 %2").arg(dt.toString()).arg(desc) 
  1999.  
  2000.                 if e.job_id:
  2001.                     job_id = unicode(e.job_id)
  2002.                 else:
  2003.                     job_id = u''
  2004.  
  2005.                 error_state = STATUS_TO_ERROR_STATE_MAP.get(e.event_code, ERROR_STATE_CLEAR)
  2006.                 tech_type = self.cur_device.tech_type
  2007.  
  2008.                 try:
  2009.                     if tech_type in (TECH_TYPE_COLOR_INK, TECH_TYPE_MONO_INK):
  2010.                         status_pix = self.STATUS_ICONS[error_state][0] # ink
  2011.                     else:
  2012.                         status_pix = self.STATUS_ICONS[error_state][1] # laser
  2013.                 except KeyError:
  2014.                     status_pix = self.STATUS_ICONS[ERROR_STATE_CLEAR][0]
  2015.  
  2016.                 StatusListViewItem(self.statusListView, status_pix, ess, tt, unicode(e.event_code), 
  2017.                     job_id, unicode(e.username))
  2018.  
  2019.                 row -= 1
  2020.  
  2021.         i = self.statusListView.firstChild()
  2022.         if i is not None:
  2023.             self.statusListView.setCurrentItem(i)
  2024.  
  2025.  
  2026.     def getTimeDeltaDesc(self, past):
  2027.         t1 = QDateTime()
  2028.         t1.setTime_t(int(past))
  2029.         t2 = QDateTime.currentDateTime()
  2030.         delta = t1.secsTo(t2)
  2031.         return self.__tr("(about %1 ago)").arg(self.stringify(delta))
  2032.  
  2033.  
  2034.     # "Nicely readable timedelta"
  2035.     # Credit: Bjorn Lindqvist
  2036.     # ASPN Python Recipe 498062 
  2037.     # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/498062
  2038.     # Note: Modified from recipe
  2039.     def seconds_in_units(self, seconds):
  2040.         unit_limits = [("year", 31536000),
  2041.                        ("month", 2592000),
  2042.                        ("week", 604800),
  2043.                        ("day", 86400),
  2044.                        ("hour", 3600),
  2045.                        ("minute", 60)]
  2046.  
  2047.         for unit_name, limit in unit_limits:
  2048.             if seconds >= limit:
  2049.                 amount = int(round(float(seconds) / limit))
  2050.                 return amount, unit_name
  2051.  
  2052.         return seconds, "second"
  2053.  
  2054.  
  2055.     def stringify(self, seconds):
  2056.         amount, unit_name = self.seconds_in_units(seconds)
  2057.  
  2058.         try:
  2059.             i18n_amount = self.num_repr[amount]
  2060.         except KeyError:
  2061.             i18n_amount = unicode(amount)
  2062.  
  2063.         if amount == 1:
  2064.             i18n_unit = self.unit_names[unit_name][0]
  2065.         else:
  2066.             i18n_unit = self.unit_names[unit_name][1]
  2067.  
  2068.         return QString("%1 %2").arg(i18n_amount).arg(i18n_unit)
  2069.  
  2070.  
  2071.  
  2072.  
  2073.     # ***********************************************************************************
  2074.     #
  2075.     # SUPPLIES TAB
  2076.     #
  2077.     # ***********************************************************************************      
  2078.  
  2079.     def InitSuppliesTab(self):
  2080.         self.pix_battery = load_pixmap('battery', '16x16')
  2081.  
  2082.         yellow = "#ffff00"
  2083.         light_yellow = "#ffffcc"
  2084.         cyan = "#00ffff"
  2085.         light_cyan = "#ccffff"
  2086.         magenta = "#ff00ff"
  2087.         light_magenta = "#ffccff"
  2088.         black = "#000000"
  2089.         blue = "#0000ff"
  2090.         dark_grey = "#808080"
  2091.         light_grey = "#c0c0c0"
  2092.  
  2093.         self.TYPE_TO_PIX_MAP = {
  2094.                                AGENT_TYPE_UNSPECIFIED : [black],
  2095.                                AGENT_TYPE_BLACK: [black],
  2096.                                AGENT_TYPE_CMY: [cyan, magenta, yellow],
  2097.                                AGENT_TYPE_KCM: [light_cyan, light_magenta, light_yellow],
  2098.                                AGENT_TYPE_GGK: [dark_grey],
  2099.                                AGENT_TYPE_YELLOW: [yellow],
  2100.                                AGENT_TYPE_MAGENTA: [magenta],
  2101.                                AGENT_TYPE_CYAN : [cyan],
  2102.                                AGENT_TYPE_CYAN_LOW: [light_cyan],
  2103.                                AGENT_TYPE_YELLOW_LOW: [light_yellow],
  2104.                                AGENT_TYPE_MAGENTA_LOW: [light_magenta],
  2105.                                AGENT_TYPE_BLUE: [blue],
  2106.                                AGENT_TYPE_KCMY_CM: [yellow, cyan, magenta],
  2107.                                AGENT_TYPE_LC_LM: [light_cyan, light_magenta],
  2108.                                #AGENT_TYPE_Y_M: [yellow, magenta],
  2109.                                #AGENT_TYPE_C_K: [black, cyan],
  2110.                                AGENT_TYPE_LG_PK: [light_grey, dark_grey],
  2111.                                AGENT_TYPE_LG: [light_grey],
  2112.                                AGENT_TYPE_G: [dark_grey],
  2113.                                AGENT_TYPE_PG: [light_grey],
  2114.                                AGENT_TYPE_C_M: [cyan, magenta],
  2115.                                AGENT_TYPE_K_Y: [black, yellow],
  2116.                                }
  2117.  
  2118.         self.suppliesList.setSorting(-1)
  2119.         self.suppliesList.setColumnText(0, QString(""))
  2120.         #self.suppliesList.setColumnWidthMode(0, QListView.Manual)
  2121.         self.suppliesList.setColumnWidth(0, 16)
  2122.         self.suppliesList.setColumnWidth(3, 100)
  2123.  
  2124.  
  2125.     def UpdateSuppliesTab(self):
  2126.         #log.debug("UpdateSuppliesTab()")
  2127.  
  2128.         self.suppliesList.clear()
  2129.  
  2130.         if self.cur_device is not None and \
  2131.             self.cur_device.supported and \
  2132.             self.cur_device.status_type != STATUS_TYPE_NONE and \
  2133.             self.cur_device.device_state != DEVICE_STATE_NOT_FOUND:
  2134.  
  2135.             try:
  2136.                 self.cur_device.sorted_supplies
  2137.             except AttributeError:                
  2138.                 self.cur_device.sorted_supplies = []
  2139.  
  2140.             if not self.cur_device.sorted_supplies:
  2141.                 a = 1
  2142.                 while True:
  2143.                     try:
  2144.                         agent_type = int(self.cur_device.dq['agent%d-type' % a])
  2145.                         agent_kind = int(self.cur_device.dq['agent%d-kind' % a])
  2146.                     except KeyError:
  2147.                         break
  2148.                     else:
  2149.                         self.cur_device.sorted_supplies.append((a, agent_kind, agent_type))
  2150.  
  2151.                     a += 1
  2152.  
  2153.                 self.cur_device.sorted_supplies.sort(lambda x, y: cmp(x[2], y[2]) or cmp(x[1], y[1]))
  2154.  
  2155.  
  2156.             for x in self.cur_device.sorted_supplies:
  2157.                 a, agent_kind, agent_type = x
  2158.                 agent_level = int(self.cur_device.dq['agent%d-level' % a])
  2159.                 agent_sku = str(self.cur_device.dq['agent%d-sku' % a])
  2160.                 agent_desc = self.cur_device.dq['agent%d-desc' % a]
  2161.                 agent_health_desc = self.cur_device.dq['agent%d-health-desc' % a]
  2162.  
  2163.                 # Bar graph level
  2164.                 level_pixmap = None
  2165.                 if agent_kind in (AGENT_KIND_SUPPLY,
  2166.                                   #AGENT_KIND_HEAD,
  2167.                                   AGENT_KIND_HEAD_AND_SUPPLY,
  2168.                                   AGENT_KIND_TONER_CARTRIDGE,
  2169.                                   AGENT_KIND_MAINT_KIT,
  2170.                                   AGENT_KIND_ADF_KIT,
  2171.                                   AGENT_KIND_INT_BATTERY,
  2172.                                   AGENT_KIND_DRUM_KIT,
  2173.                                   ):
  2174.  
  2175.                     level_pixmap = self.createBarGraph(agent_level, agent_type)
  2176.  
  2177.                 # Color icon
  2178.                 pixmap = None
  2179.                 if agent_kind in (AGENT_KIND_SUPPLY,
  2180.                                   AGENT_KIND_HEAD,
  2181.                                   AGENT_KIND_HEAD_AND_SUPPLY,
  2182.                                   AGENT_KIND_TONER_CARTRIDGE,
  2183.                                   #AGENT_KIND_MAINT_KIT,
  2184.                                   #AGENT_KIND_ADF_KIT,
  2185.                                   AGENT_KIND_INT_BATTERY,
  2186.                                   #AGENT_KIND_DRUM_KIT,
  2187.                                   ):
  2188.  
  2189.                     pixmap = self.getIcon(agent_kind, agent_type)
  2190.  
  2191.  
  2192.                 SuppliesListViewItem(self.suppliesList, pixmap, agent_desc, 
  2193.                     agent_sku, level_pixmap, agent_health_desc)
  2194.  
  2195.             i = self.suppliesList.firstChild()
  2196.             if i is not None:
  2197.                 self.suppliesList.setCurrentItem(i)
  2198.  
  2199.  
  2200.  
  2201.  
  2202.     def getIcon(self, agent_kind, agent_type):
  2203.         if agent_kind in (AGENT_KIND_SUPPLY,
  2204.                           AGENT_KIND_HEAD,
  2205.                           AGENT_KIND_HEAD_AND_SUPPLY,
  2206.                           AGENT_KIND_TONER_CARTRIDGE):
  2207.  
  2208.             map = self.TYPE_TO_PIX_MAP[agent_type]
  2209.  
  2210.             if isinstance(map, list):
  2211.                 map_len = len(map)
  2212.                 pix = QPixmap(16, 16) #, -1, QPixmap.DefaultOptim)
  2213.                 pix.fill(qApp.palette().color(QPalette.Active, QColorGroup.Background))
  2214.                 p = QPainter()
  2215.                 p.begin(pix)
  2216.                 p.setBackgroundMode(Qt.OpaqueMode)
  2217.  
  2218.                 if map_len == 1:
  2219.                     p.setPen(QColor(map[0]))
  2220.                     p.setBrush(QBrush(QColor(map[0]), Qt.SolidPattern))
  2221.                     p.drawPie(2, 2, 10, 10, 0, 5760)
  2222.  
  2223.                 elif map_len == 2:
  2224.                     p.setPen(QColor(map[0]))
  2225.                     p.setBrush(QBrush(QColor(map[0]), Qt.SolidPattern))
  2226.                     p.drawPie(2, 4, 8, 8, 0, 5760)
  2227.  
  2228.                     p.setPen(QColor(map[1]))
  2229.                     p.setBrush(QBrush(QColor(map[1]), Qt.SolidPattern))
  2230.                     p.drawPie(6, 4, 8, 8, 0, 5760)
  2231.  
  2232.                 elif map_len == 3:
  2233.                     p.setPen(QColor(map[2]))
  2234.                     p.setBrush(QBrush(QColor(map[2]), Qt.SolidPattern))
  2235.                     p.drawPie(6, 6, 8, 8, 0, 5760)
  2236.  
  2237.                     p.setPen(QColor(map[1]))
  2238.                     p.setBrush(QBrush(QColor(map[1]), Qt.SolidPattern))
  2239.                     p.drawPie(2, 6, 8, 8, 0, 5760)
  2240.  
  2241.                     p.setPen(QColor(map[0]))
  2242.                     p.setBrush(QBrush(QColor(map[0]), Qt.SolidPattern))
  2243.                     p.drawPie(4, 2, 8, 8, 0, 5760)
  2244.  
  2245.                 p.end()
  2246.                 return pix
  2247.  
  2248.             else:
  2249.                 return map
  2250.  
  2251.         elif agent_kind == AGENT_KIND_INT_BATTERY:
  2252.                 return self.pix_battery
  2253.  
  2254.  
  2255.     def createBarGraph(self, percent, agent_type, w=100, h=18):
  2256.         fw = w/100*percent
  2257.         px = QPixmap(w, h)
  2258.         px.fill(qApp.palette().color(QPalette.Active, QColorGroup.Background))
  2259.  
  2260.         pp = QPainter(px)
  2261.         pp.setPen(Qt.black)
  2262.         pp.setBackgroundColor(qApp.palette().color(QPalette.Active, QColorGroup.Base))
  2263.  
  2264.         map = self.TYPE_TO_PIX_MAP[agent_type]
  2265.         map_len = len(map)
  2266.  
  2267.         if map_len == 1 or map_len > 3:
  2268.             pp.fillRect(0, 0, fw, h, QBrush(QColor(map[0])))
  2269.  
  2270.         elif map_len == 2:
  2271.             h2 = h / 2
  2272.             pp.fillRect(0, 0, fw, h2, QBrush(QColor(map[0])))
  2273.             pp.fillRect(0, h2, fw, h, QBrush(QColor(map[1])))
  2274.  
  2275.         elif map_len == 3:
  2276.             h3 = h / 3
  2277.             h23 = 2 * h3
  2278.             pp.fillRect(0, 0, fw, h3, QBrush(QColor(map[0])))
  2279.             pp.fillRect(0, h3, fw, h23, QBrush(QColor(map[1])))
  2280.             pp.fillRect(0, h23, fw, h, QBrush(QColor(map[2])))
  2281.  
  2282.         # draw black frame
  2283.         pp.drawRect(0, 0, w, h)
  2284.  
  2285.         if percent > 75 and agent_type in \
  2286.           (AGENT_TYPE_BLACK, AGENT_TYPE_UNSPECIFIED, AGENT_TYPE_BLUE):
  2287.             pp.setPen(Qt.white)
  2288.  
  2289.         # 75% ticks
  2290.         w1 = 3 * w / 4
  2291.         h6 = h / 6
  2292.         pp.drawLine(w1, 0, w1, h6)
  2293.         pp.drawLine(w1, h, w1, h-h6)
  2294.  
  2295.         if percent > 50 and agent_type in \
  2296.           (AGENT_TYPE_BLACK, AGENT_TYPE_UNSPECIFIED, AGENT_TYPE_BLUE):
  2297.             pp.setPen(Qt.white)
  2298.  
  2299.         # 50% ticks
  2300.         w2 = w / 2
  2301.         h4 = h / 4
  2302.         pp.drawLine(w2, 0, w2, h4)
  2303.         pp.drawLine(w2, h, w2, h-h4)
  2304.  
  2305.         if percent > 25 and agent_type in \
  2306.           (AGENT_TYPE_BLACK, AGENT_TYPE_UNSPECIFIED, AGENT_TYPE_BLUE):
  2307.             pp.setPen(Qt.white)
  2308.  
  2309.         # 25% ticks
  2310.         w4 = w / 4
  2311.         pp.drawLine(w4, 0, w4, h6)
  2312.         pp.drawLine(w4, h, w4, h-h6)
  2313.  
  2314.         return px   
  2315.  
  2316.  
  2317.  
  2318.     # ***********************************************************************************
  2319.     #
  2320.     # PRINTER SETTINGS TAB
  2321.     #
  2322.     # ***********************************************************************************
  2323.  
  2324.     def InitPrintSettingsTab(self): # Add Scrolling Print Settings
  2325.         PrintJobsTabLayout = QGridLayout(self.PrintSettingsTab,1,1,11,6,"PrintJobsTabLayout")
  2326.  
  2327.         self.PrintSettingsList = ScrollPrintSettingsView(self.service, self.PrintSettingsTab, "PrintSettingsView")
  2328.         PrintJobsTabLayout.addMultiCellWidget(self.PrintSettingsList,1,1,0,3)
  2329.  
  2330.         self.PrintSettingsPrinterCombo = QComboBox(0,self.PrintSettingsTab,"comboBox5")
  2331.  
  2332.         self.PrintSettingsPrinterCombo.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed,0,0,
  2333.             self.PrintSettingsPrinterCombo.sizePolicy().hasHeightForWidth()))
  2334.  
  2335.         PrintJobsTabLayout.addWidget(self.PrintSettingsPrinterCombo, 0, 2)
  2336.  
  2337.         self.settingTextLabel = QLabel(self.PrintSettingsTab,"self.settingTextLabel")
  2338.         PrintJobsTabLayout.addWidget(self.settingTextLabel,0,1)
  2339.  
  2340.         self.settingTextLabel.setText(self.__tr("Printer Name:"))
  2341.  
  2342.         spacer34 = QSpacerItem(20,20,QSizePolicy.Preferred, QSizePolicy.Minimum)
  2343.         PrintJobsTabLayout.addItem(spacer34,0,3) 
  2344.  
  2345.         spacer35 = QSpacerItem(20,20,QSizePolicy.Preferred, QSizePolicy.Minimum)
  2346.         PrintJobsTabLayout.addItem(spacer35,0,0)
  2347.  
  2348.         self.connect(self.PrintSettingsPrinterCombo, SIGNAL("activated(const QString&)"), 
  2349.             self.PrintSettingsPrinterCombo_activated)
  2350.  
  2351.  
  2352.     def UpdatePrintSettingsTab(self):
  2353.         #log.debug("UpdatePrintSettingsTab()")
  2354.         if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
  2355.             self.settingTextLabel.setText(self.__tr("Printer Name:"))
  2356.         else:
  2357.             self.settingTextLabel.setText(self.__tr("Fax Name:"))
  2358.  
  2359.         self.PrintSettingsList.onDeviceChange(self.cur_device)
  2360.  
  2361.  
  2362.     def UpdatePrintSettingsTabPrinter(self):
  2363.         self.PrintSettingsList.onPrinterChange(self.cur_printer)
  2364.  
  2365.  
  2366.     # ***********************************************************************************
  2367.     #
  2368.     # PRINTER CONTROL TAB
  2369.     #
  2370.     # ***********************************************************************************
  2371.  
  2372.     def InitPrintControlTab(self):
  2373.         self.JOB_STATES = { cups.IPP_JOB_PENDING : self.__tr("Pending"),
  2374.                             cups.IPP_JOB_HELD : self.__tr("On hold"),
  2375.                             cups.IPP_JOB_PROCESSING : self.__tr("Printing"),
  2376.                             cups.IPP_JOB_STOPPED : self.__tr("Stopped"),
  2377.                             cups.IPP_JOB_CANCELLED : self.__tr("Canceled"),
  2378.                             cups.IPP_JOB_ABORTED : self.__tr("Aborted"),
  2379.                             cups.IPP_JOB_COMPLETED : self.__tr("Completed"),
  2380.                            }
  2381.  
  2382.         self.cancelToolButton.setIconSet(QIconSet(load_pixmap('cancel', '16x16')))
  2383.         self.infoToolButton.setIconSet(QIconSet(load_pixmap('info', '16x16')))
  2384.  
  2385.         self.JOB_STATE_ICONS = { cups.IPP_JOB_PENDING: self.busy_pix,
  2386.                                  cups.IPP_JOB_HELD : self.busy_pix,
  2387.                                  cups.IPP_JOB_PROCESSING : self.print_pix,
  2388.                                  cups.IPP_JOB_STOPPED : self.warning_pix,
  2389.                                  cups.IPP_JOB_CANCELLED : self.warning_pix,
  2390.                                  cups.IPP_JOB_ABORTED : self.error_pix,
  2391.                                  cups.IPP_JOB_COMPLETED : self.ok_pix,
  2392.                                 }        
  2393.  
  2394.         self.jobList.setSorting(-1)
  2395.         self.jobList.setColumnText(0, QString(""))
  2396.         #self.jobList.setColumnWidthMode(0, QListView.Manual)
  2397.         self.jobList.setColumnWidth(0, 16)
  2398.         self.jobList.setColumnText(1, QString(""))
  2399.         #self.jobList.setColumnWidthMode(1, QListView.Manual)
  2400.         self.jobList.setColumnWidth(1, 16)
  2401.         self.jobList.setColumnWidth(2, 300)
  2402.         self.cancelToolButton.setEnabled(False)
  2403.         self.infoToolButton.setEnabled(False)
  2404.  
  2405.         self.printer_state = cups.IPP_PRINTER_STATE_IDLE
  2406.  
  2407.         # TODO: Check queues at startup and send events if stopped or rejecting
  2408.  
  2409.  
  2410.     def UpdatePrintControlTab(self):
  2411.         #log.debug("UpdatePrintControlTab()")
  2412.  
  2413.         if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
  2414.             self.printerTextLabel.setText(self.__tr("Printer Name:"))
  2415.         
  2416.         else:
  2417.             self.printerTextLabel.setText(self.__tr("Fax Name:"))
  2418.  
  2419.         self.jobList.clear()
  2420.         self.UpdatePrintController()
  2421.  
  2422.         jobs = cups.getJobs()
  2423.         num_jobs = 0
  2424.         for j in jobs:
  2425.             if j.dest.decode('utf-8') == unicode(self.cur_printer):
  2426.                 num_jobs += 1
  2427.  
  2428.         for j in jobs:
  2429.             if j.dest == self.cur_printer:
  2430.                 JobListViewItem(self.jobList, self.JOB_STATE_ICONS[j.state], 
  2431.                     j.title, self.JOB_STATES[j.state], unicode(j.id))
  2432.  
  2433.         i = self.jobList.firstChild()
  2434.         if i is not None:
  2435.             self.jobList.setCurrentItem(i)
  2436.  
  2437.  
  2438.     def jobList_clicked(self, i):
  2439.         num = 0    
  2440.         item = self.jobList.firstChild()
  2441.         while item is not None:
  2442.             if item.isOn():
  2443.                 num += 1
  2444.  
  2445.             item = item.nextSibling()   
  2446.  
  2447.         self.cancelToolButton.setEnabled(num)
  2448.         self.infoToolButton.setEnabled(num == 1)
  2449.  
  2450.  
  2451.     def infoToolButton_clicked(self):
  2452.         item = self.jobList.firstChild()
  2453.         while item is not None:
  2454.             if item.isOn():
  2455.                 return self.showJobInfoDialog(item)
  2456.  
  2457.             item = item.nextSibling()
  2458.  
  2459.  
  2460.     def cancelToolButton_clicked(self):
  2461.         self.cancelCheckedJobs()
  2462.  
  2463.  
  2464.     def jobList_contextMenuRequested(self, item, pos, a2):
  2465.         if item is not None and item is self.jobList.currentItem():
  2466.             popup = QPopupMenu(self)
  2467.  
  2468.             popup.insertItem(self.__tr("Cancel Job"), self.cancelJob)
  2469.             popup.insertSeparator()
  2470.             popup.insertItem(self.__tr("View Job Log (advanced)..."), self.getJobInfo)
  2471.  
  2472.             popup.popup(pos)
  2473.  
  2474.  
  2475.     def cancelJob(self):
  2476.         item = self.jobList.currentItem()
  2477.  
  2478.         if item is not None:
  2479.             self.cur_device.cancelJob(item.job_id)
  2480.  
  2481.  
  2482.     def getJobInfo(self):
  2483.         return self.showJobInfoDialog(self.jobList.currentItem())
  2484.  
  2485.  
  2486.     def showJobInfoDialog(self, item):
  2487.         if item is not None:
  2488.             text = cups.getPrintJobErrorLog(int(item.job_id))
  2489.  
  2490.             if text:
  2491.                 dlg = JobInfoDialog(text, self)
  2492.                 dlg.setCaption(self.__tr("HP Device Manager - Job Log - %1 - Job %2").\
  2493.                     arg(self.cur_printer).arg(unicode(item.job_id)))
  2494.  
  2495.                 dlg.exec_loop()
  2496.             
  2497.             else:
  2498.                 self.FailureUI(self.__tr("<b>No log output found.</b><p>If the print job is stopped or the printer is rejecting jobs, there might not be any output. Also, you will receive more output in the CUPS LogLevel is set to 'debug'."))          
  2499.  
  2500.  
  2501.     def UpdatePrintController(self):
  2502.         # default printer
  2503.         self.defaultPushButton.setText(self.__tr("Set as Default"))
  2504.  
  2505.         default_printer = cups.getDefaultPrinter()
  2506.         if default_printer is not None:
  2507.             default_printer = default_printer.decode('utf8')
  2508.  
  2509.         if default_printer == self.cur_printer:
  2510.             s = self.__tr("SET AS DEFAULT")
  2511.             self.defaultPushButton.setEnabled(False)
  2512.         
  2513.         else:
  2514.             s = self.__tr("NOT SET AS DEFAULT")
  2515.             self.defaultPushButton.setEnabled(True)
  2516.  
  2517.         if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
  2518.             QToolTip.add(self.defaultPushButton, self.__tr("The printer is currently: %1").arg(s))
  2519.         
  2520.         else:
  2521.             QToolTip.add(self.defaultPushButton, self.__tr("The fax is currently: %1").arg(s))
  2522.  
  2523.         self.printer_state = cups.IPP_PRINTER_STATE_IDLE
  2524.  
  2525.         cups_printers = cups.getPrinters()
  2526.         
  2527.         for p in cups_printers:
  2528.             if p.name.decode('utf-8') == self.cur_printer:
  2529.                 self.printer_state = p.state
  2530.                 self.printer_accepting = p.accepting
  2531.                 break
  2532.  
  2533.         # start/stop
  2534.         if self.printer_state == cups.IPP_PRINTER_STATE_IDLE:
  2535.             s = self.__tr("IDLE")
  2536.             
  2537.             if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
  2538.                 self.stopstartPushButton.setText(self.__tr("Stop Printer"))
  2539.             
  2540.             else:
  2541.                 self.stopstartPushButton.setText(self.__tr("Stop Fax"))
  2542.  
  2543.         elif self.printer_state == cups.IPP_PRINTER_STATE_PROCESSING:
  2544.             s = self.__tr("PROCESSING")
  2545.             
  2546.             if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
  2547.                 self.stopstartPushButton.setText(self.__tr("Stop Printer"))
  2548.             
  2549.             else:
  2550.                 self.stopstartPushButton.setText(self.__tr("Stop Fax"))
  2551.         else:
  2552.             s = self.__tr("STOPPED")
  2553.             
  2554.             if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
  2555.                 self.stopstartPushButton.setText(self.__tr("Start Printer"))
  2556.             
  2557.             else:
  2558.                 self.stopstartPushButton.setText(self.__tr("Start Fax"))
  2559.  
  2560.         if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
  2561.             QToolTip.add(self.stopstartPushButton, self.__tr("The printer is currently: %1").arg(s))
  2562.         
  2563.         else:
  2564.             QToolTip.add(self.stopstartPushButton, self.__tr("The fax is currently: %1").arg(s))
  2565.  
  2566.         # reject/accept
  2567.         if self.printer_accepting:
  2568.             s = self.__tr("ACCEPTING JOBS")
  2569.             self.rejectacceptPushButton.setText(self.__tr("Reject Jobs"))
  2570.         
  2571.         else:
  2572.             s = self.__tr("REJECTING JOBS")
  2573.             self.rejectacceptPushButton.setText(self.__tr("Accept Jobs"))
  2574.  
  2575.         if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
  2576.             QToolTip.add(self.rejectacceptPushButton, self.__tr("The printer is currently: %1").arg(s))
  2577.         
  2578.         else:
  2579.             QToolTip.add(self.rejectacceptPushButton, self.__tr("The fax is currently: %1").arg(s))
  2580.  
  2581.  
  2582.     def stopstartPushButton_clicked(self):
  2583.         QApplication.setOverrideCursor(QApplication.waitCursor)
  2584.         try:
  2585.             if self.printer_state in (cups.IPP_PRINTER_STATE_IDLE, cups.IPP_PRINTER_STATE_PROCESSING):
  2586.                 cups.stop(self.cur_printer)
  2587.                 
  2588.                 if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
  2589.                     e = EVENT_PRINTER_QUEUE_STOPPED
  2590.                 else:
  2591.                     e = EVENT_FAX_QUEUE_STOPPED
  2592.  
  2593.             else:
  2594.                 cups.start(self.cur_printer)
  2595.                 
  2596.                 if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
  2597.                     e = EVENT_PRINTER_QUEUE_STARTED
  2598.                 else:
  2599.                     e = EVENT_FAX_QUEUE_STARTED
  2600.  
  2601.             self.UpdatePrintController()
  2602.             self.cur_device.sendEvent(e, self.cur_printer)
  2603.         
  2604.         finally:
  2605.             QApplication.restoreOverrideCursor()
  2606.  
  2607.  
  2608.     def rejectacceptPushButton_clicked(self):
  2609.         QApplication.setOverrideCursor(QApplication.waitCursor)
  2610.         try:
  2611.             if self.printer_accepting:
  2612.                 cups.reject(self.cur_printer)
  2613.                 if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
  2614.                     e = EVENT_PRINTER_QUEUE_REJECTING_JOBS
  2615.                 else:
  2616.                     e = EVENT_FAX_QUEUE_REJECTING_JOBS
  2617.             else:
  2618.                 cups.accept(self.cur_printer)
  2619.                 if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
  2620.                     e = EVENT_PRINTER_QUEUE_ACCEPTING_JOBS
  2621.                 else:
  2622.                     e = EVENT_FAX_QUEUE_ACCEPTING_JOBS
  2623.  
  2624.             self.UpdatePrintController()
  2625.             self.cur_device.sendEvent(e, self.cur_printer)
  2626.         
  2627.         finally:
  2628.             QApplication.restoreOverrideCursor()
  2629.  
  2630.  
  2631.     def defaultPushButton_clicked(self):
  2632.         QApplication.setOverrideCursor(QApplication.waitCursor)
  2633.         try:
  2634.             result = cups.setDefaultPrinter(self.cur_printer.encode('utf8'))
  2635.             if not result:
  2636.                 log.error("Set default printer failed.")
  2637.             else:
  2638.                 self.UpdatePrintController()
  2639.                 if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
  2640.                     e = EVENT_PRINTER_QUEUE_SET_AS_DEFAULT
  2641.                 else:
  2642.                     e = EVENT_FAX_QUEUE_SET_AS_DEFAULT
  2643.  
  2644.                 self.cur_device.sendEvent(e, self.cur_printer)
  2645.         
  2646.         finally:
  2647.             QApplication.restoreOverrideCursor()
  2648.  
  2649.  
  2650.     def cancelCheckedJobs(self):
  2651.         QApplication.setOverrideCursor(QApplication.waitCursor)
  2652.         try:
  2653.             item = self.jobList.firstChild()
  2654.             while item is not None:
  2655.                 if item.isOn():
  2656.                     self.cur_device.cancelJob(item.job_id)
  2657.  
  2658.                 item = item.nextSibling() 
  2659.         
  2660.         finally:
  2661.             QApplication.restoreOverrideCursor()
  2662.  
  2663.         self.UpdatePrintControlTab()
  2664.  
  2665.         
  2666.         
  2667.  
  2668.     # ***********************************************************************************
  2669.     #
  2670.     # EXIT/CHILD CLEANUP
  2671.     #
  2672.     # ***********************************************************************************
  2673.  
  2674.     def closeEvent(self, event):
  2675.         self.Cleanup()
  2676.         self.request_queue.put(None)
  2677.         event.accept()
  2678.  
  2679.  
  2680.     def Cleanup(self):
  2681.         self.request_queue.put(None)
  2682.         self.CleanupChildren()
  2683.         if not self.update_thread.wait(5000):
  2684.             self.update_thread.terminate()
  2685.  
  2686.  
  2687.     def CleanupChildren(self):
  2688.         log.debug("Cleaning up child processes.")
  2689.         try:
  2690.             os.waitpid(-1, os.WNOHANG)
  2691.         except OSError:
  2692.             pass    
  2693.  
  2694.  
  2695.     # ***********************************************************************************   
  2696.     #
  2697.     # DEVICE SETTINGS PLUGIN
  2698.     #
  2699.     # ***********************************************************************************
  2700.  
  2701.     def CheckForDeviceSettingsUI(self, dev):
  2702.         dev.device_settings_ui = None
  2703.         name = '.'.join(['plugins', dev.model])
  2704.         log.debug("Attempting to load plugin: %s" % name)
  2705.         try:
  2706.             mod = __import__(name, globals(), locals(), [])
  2707.         except ImportError:
  2708.             log.debug("No plugin found.")
  2709.             return
  2710.         else:
  2711.             components = name.split('.')
  2712.             for c in components[1:]:
  2713.                 mod = getattr(mod, c)
  2714.             log.debug("Loaded: %s" % repr(mod))
  2715.             dev.device_settings_ui = mod.settingsUI
  2716.  
  2717.  
  2718.     # ***********************************************************************************
  2719.     #
  2720.     # SETTINGS DIALOG
  2721.     #
  2722.     # ***********************************************************************************
  2723.  
  2724.     def settingsConfigure_activated(self, tab_to_show=0):
  2725.         dlg = SettingsDialog(self)
  2726.         dlg.TabWidget.setCurrentPage(tab_to_show)
  2727.  
  2728.         if dlg.exec_loop() == QDialog.Accepted:
  2729.             old_auto_refresh = self.user_settings.auto_refresh_rate
  2730.             self.user_settings.load()
  2731.  
  2732.             if self.user_settings.auto_refresh and old_auto_refresh != self.user_settings.auto_refresh_rate:
  2733.                 self.refresh_timer.changeInterval(self.user_settings.auto_refresh_rate * 1000)
  2734.  
  2735.             if old_auto_refresh != self.user_settings.auto_refresh:
  2736.                 self.autoRefresh.toggle()        
  2737.  
  2738.  
  2739.     # ***********************************************************************************
  2740.     #
  2741.     # SETUP/REMOVE
  2742.     #
  2743.     # ***********************************************************************************         
  2744.  
  2745.     def deviceInstallAction_activated(self):
  2746.         su_sudo = None
  2747.  
  2748.         if utils.which('kdesu'):
  2749.             su_sudo = 'kdesu -- %s'
  2750.  
  2751.         elif utils.which('kdesudo'):
  2752.             su_sudo = 'kdesudo -- %s'
  2753.  
  2754.         elif utils.which('gnomesu'):
  2755.             su_sudo = 'gnomesu -c "%s"'
  2756.         
  2757.         elif utils.which('gksu'):
  2758.             su_sudo = 'gksu "%s"'
  2759.  
  2760.         if su_sudo is None:
  2761.             QMessageBox.critical(self,
  2762.                 self.caption(),
  2763.                 self.__tr("<b>Unable to find an appropriate su/sudo utility to run hp-setup.</b>"),
  2764.                 QMessageBox.Ok,
  2765.                 QMessageBox.NoButton,
  2766.                 QMessageBox.NoButton)
  2767.  
  2768.         else:
  2769.             if utils.which('hp-setup'):
  2770.                 cmd = su_sudo % 'hp-setup -u'
  2771.             else:
  2772.                 cmd = su_sudo % 'python ./setup.py -u'
  2773.  
  2774.             log.debug(cmd)
  2775.             utils.run(cmd, log_output=True, password_func=None, timeout=1)
  2776.             self.RescanDevices()        
  2777.  
  2778.  
  2779.     def deviceRemoveAction_activated(self):
  2780.         if self.cur_device is not None:
  2781.             x = QMessageBox.critical(self,
  2782.            self.caption(),
  2783.            self.__tr("<b>Annoying Confirmation: Are you sure you want to remove this device?</b>"),
  2784.             QMessageBox.Yes,
  2785.             QMessageBox.No | QMessageBox.Default,
  2786.             QMessageBox.NoButton)
  2787.             if x == QMessageBox.Yes:
  2788.                 QApplication.setOverrideCursor(QApplication.waitCursor)
  2789.                 print_uri = self.cur_device.device_uri
  2790.                 fax_uri = print_uri.replace('hp:', 'hpfax:')
  2791.  
  2792.                 log.debug(print_uri)
  2793.                 log.debug(fax_uri)
  2794.  
  2795.                 self.cups_devices = device.getSupportedCUPSDevices(['hp', 'hpfax'])
  2796.  
  2797.                 for d in self.cups_devices:
  2798.                     if d in (print_uri, fax_uri):
  2799.                         for p in self.cups_devices[d]:
  2800.                             log.debug("Removing %s" % p)
  2801.                             cups.delPrinter(p)
  2802.  
  2803.                 self.cur_device = None
  2804.                 self.cur_device_uri = ''
  2805.                 user_cfg.last_used.device_uri = ''
  2806.  
  2807.                 QApplication.restoreOverrideCursor()
  2808.  
  2809.                 self.RescanDevices()
  2810.  
  2811.  
  2812.     # ***********************************************************************************
  2813.     #
  2814.     # MISC
  2815.     #
  2816.     # ***********************************************************************************
  2817.  
  2818.     
  2819.     def RunCommand(self, cmd, macro_char='%'):
  2820.         QApplication.setOverrideCursor(QApplication.waitCursor)
  2821.  
  2822.         try:
  2823.             if len(cmd) == 0:
  2824.                 self.FailureUI(self.__tr("<p><b>Unable to run command. No command specified.</b><p>Use <pre>Configure...</pre> to specify a command to run."))
  2825.                 log.error("No command specified. Use settings to configure commands.")
  2826.             else:
  2827.                 log.debug("Run: %s %s (%s) %s" % ("*"*20, cmd, self.cur_device_uri, "*"*20))
  2828.                 log.debug(cmd)
  2829.  
  2830.                 try:
  2831.                     cmd = ''.join([self.cur_device.device_vars.get(x, x) \
  2832.            for x in cmd.split(macro_char)])
  2833.                 except AttributeError:
  2834.                     pass
  2835.  
  2836.                 log.debug(cmd)
  2837.  
  2838.                 path = cmd.split()[0]
  2839.                 args = cmd.split()
  2840.  
  2841.                 log.debug(path)
  2842.                 log.debug(args)
  2843.  
  2844.                 self.CleanupChildren()
  2845.                 os.spawnvp(os.P_NOWAIT, path, args)
  2846.                 qApp.processEvents()
  2847.  
  2848.         finally:
  2849.             QApplication.restoreOverrideCursor()
  2850.  
  2851.  
  2852.     def helpContents(self):
  2853.         f = "http://hplip.sf.net"
  2854.  
  2855.         if prop.doc_build:
  2856.             g = os.path.join(sys_cfg.dirs.doc, 'index.html')
  2857.             if os.path.exists(g):
  2858.                 f = "file://%s" % g
  2859.  
  2860.         log.debug(f)
  2861.         utils.openURL(f)
  2862.  
  2863.  
  2864.     def helpAbout(self):
  2865.         dlg = AboutDlg(self)
  2866.         dlg.VersionText.setText(prop.version)
  2867.         dlg.ToolboxVersionText.setText(self.toolbox_version)
  2868.         dlg.exec_loop()
  2869.  
  2870.  
  2871.     def FailureUI(self, error_text):
  2872.         QMessageBox.critical(self,
  2873.             self.caption(),
  2874.             error_text,
  2875.             QMessageBox.Ok,
  2876.             QMessageBox.NoButton,
  2877.             QMessageBox.NoButton)
  2878.  
  2879.  
  2880.     def WarningUI(self, msg):
  2881.         QMessageBox.warning(self,
  2882.             self.caption(),
  2883.             msg,
  2884.             QMessageBox.Ok,
  2885.             QMessageBox.NoButton,
  2886.             QMessageBox.NoButton)
  2887.  
  2888.  
  2889.     def __tr(self,s,c = None):
  2890.         return qApp.translate("DevMgr4",s,c)
  2891.  
  2892.  
  2893.  
  2894. # ***********************************************************************************
  2895. #
  2896. # ScrollDeviceInfoView (View Device Information)
  2897. #
  2898. # ***********************************************************************************
  2899.  
  2900. class ScrollDeviceInfoView(ScrollView):
  2901.     def __init__(self, service, parent=None, form=None, name=None, fl=0):
  2902.         ScrollView.__init__(self, service, parent, name, fl)
  2903.  
  2904.  
  2905.     def fillControls(self):
  2906.         ScrollView.fillControls(self)
  2907.         self.addDeviceInfo()
  2908.         self.maximizeControl()
  2909.  
  2910.  
  2911.     def addDeviceInfo(self):
  2912.         self.addGroupHeading("info_title", self.__tr("Device Information"))
  2913.  
  2914.         widget = self.getWidget()
  2915.  
  2916.         layout37 = QGridLayout(widget,1,1,5,10,"layout37")
  2917.  
  2918.         self.infoListView = QListView(widget,"fileListView")
  2919.         self.infoListView.addColumn(self.__tr("Static/Dynamic"))
  2920.         self.infoListView.addColumn(self.__tr("Key"))
  2921.         self.infoListView.addColumn(self.__tr("Value"))
  2922.         self.infoListView.setAllColumnsShowFocus(1)
  2923.         self.infoListView.setShowSortIndicator(1)
  2924.         self.infoListView.setColumnWidth(0, 50)
  2925.         self.infoListView.setColumnWidth(1, 150)
  2926.         self.infoListView.setColumnWidth(2, 300)
  2927.         self.infoListView.setItemMargin(2)
  2928.         self.infoListView.setSorting(-1)
  2929.  
  2930.         layout37.addMultiCellWidget(self.infoListView,1,1,0,3)
  2931.  
  2932.         mq_keys = self.cur_device.mq.keys()
  2933.         mq_keys.sort()
  2934.         mq_keys.reverse()
  2935.         for key,i in zip(mq_keys, range(len(mq_keys))):
  2936.             QListViewItem(self.infoListView, self.__tr("Static"), key, str(self.cur_device.mq[key]))
  2937.  
  2938.         dq_keys = self.cur_device.dq.keys()
  2939.         dq_keys.sort()
  2940.         dq_keys.reverse()
  2941.         for key,i in zip(dq_keys, range(len(dq_keys))):
  2942.             QListViewItem(self.infoListView, self.__tr("Dynamic"), key, str(self.cur_device.dq[key]))
  2943.  
  2944.         self.addWidget(widget, "file_list", maximize=True)
  2945.  
  2946.  
  2947.     def __tr(self,s,c = None):
  2948.         return qApp.translate("ScrollDeviceInfoView",s,c)
  2949.  
  2950.  
  2951.  
  2952. # ***********************************************************************************
  2953. #
  2954. # ScrollTestpageView (Print Test Page)
  2955. #
  2956. # ***********************************************************************************
  2957.  
  2958. class ScrollTestpageView(ScrollView):
  2959.     def __init__(self, service, parent=None, form=None, name=None, fl=0):
  2960.         ScrollView.__init__(self, service, parent, name, fl)
  2961.         self.dialog = parent
  2962.  
  2963.  
  2964.     def fillControls(self):
  2965.         ScrollView.fillControls(self)
  2966.  
  2967.         if self.addPrinterFaxList():
  2968.             self.addTestpageType()
  2969.  
  2970.             self.addLoadPaper()
  2971.  
  2972.             self.printButton = self.addActionButton("bottom_nav", self.__tr("Print Test Page"), 
  2973.                 self.printButton_clicked, 'print.png', None)
  2974.  
  2975.  
  2976.     def addTestpageType(self):
  2977.         self.addGroupHeading("testpage_type", self.__tr("Test Page Type"))
  2978.         widget = self.getWidget()
  2979.  
  2980.         Form4Layout = QGridLayout(widget,1,1,5,10,"Form4Layout")
  2981.  
  2982.         self.buttonGroup3 = QButtonGroup(widget,"buttonGroup3")
  2983.         self.buttonGroup3.setLineWidth(0)
  2984.         self.buttonGroup3.setColumnLayout(0,Qt.Vertical)
  2985.         self.buttonGroup3.layout().setSpacing(5)
  2986.         self.buttonGroup3.layout().setMargin(10)
  2987.  
  2988.         buttonGroup3Layout = QGridLayout(self.buttonGroup3.layout())
  2989.         buttonGroup3Layout.setAlignment(Qt.AlignTop)
  2990.  
  2991.         self.radioButton6 = QRadioButton(self.buttonGroup3,"radioButton6")
  2992.         self.radioButton6.setEnabled(False)
  2993.         buttonGroup3Layout.addWidget(self.radioButton6,1,0)
  2994.  
  2995.         self.radioButton5 = QRadioButton(self.buttonGroup3,"radioButton5")
  2996.         self.radioButton5.setChecked(1)
  2997.         buttonGroup3Layout.addWidget(self.radioButton5,0,0)
  2998.  
  2999.         Form4Layout.addWidget(self.buttonGroup3,0,0)
  3000.  
  3001.         self.radioButton6.setText(self.__tr("Printer diagnostic page (does not test print driver)"))
  3002.         self.radioButton5.setText(self.__tr("HPLIP test page (tests print driver)"))
  3003.  
  3004.         self.addWidget(widget, "page_type")
  3005.  
  3006.  
  3007.     def printButton_clicked(self):
  3008.         d = self.cur_device
  3009.         printer_name = self.cur_printer
  3010.         printed = False
  3011.  
  3012.         try:
  3013.             QApplication.setOverrideCursor(QApplication.waitCursor)
  3014.  
  3015.             try:
  3016.                 d.open()
  3017.             except Error:
  3018.                 self.CheckDeviceUI()
  3019.             else:
  3020.                 if d.isIdleAndNoError():
  3021.                     QApplication.restoreOverrideCursor()
  3022.                     d.close()
  3023.  
  3024.                     d.printTestPage(printer_name)
  3025.                     printed = True
  3026.  
  3027.                 else:
  3028.                     d.close()
  3029.                     self.CheckDeviceUI()
  3030.  
  3031.         finally:
  3032.             QApplication.restoreOverrideCursor()
  3033.  
  3034.         if printed:
  3035.             QMessageBox.information(self,
  3036.                 self.caption(),
  3037.                 self.__tr("<p><b>A test page should be printing on your printer.</b><p>If the page fails to print, please visit http://hplip.sourceforge.net for troubleshooting and support."),
  3038.                 QMessageBox.Ok,
  3039.                 QMessageBox.NoButton,
  3040.                 QMessageBox.NoButton)
  3041.  
  3042.         self.dialog.accept()
  3043.  
  3044.  
  3045.     def CheckDeviceUI(self):
  3046.             self.FailureUI(self.__tr("<b>Device is busy or in an error state.</b><p>Please check device and try again."))            
  3047.  
  3048.         
  3049.     def FailureUI(self, error_text):
  3050.         QMessageBox.critical(self,
  3051.             self.caption(),
  3052.             error_text,
  3053.             QMessageBox.Ok,
  3054.             QMessageBox.NoButton,
  3055.             QMessageBox.NoButton)
  3056.  
  3057.  
  3058.     def __tr(self,s,c = None):
  3059.         return qApp.translate("ScrollTestpageView",s,c)
  3060.  
  3061. # ***********************************************************************************
  3062. #
  3063. # ScrollPrinterInfoView (View Device Information)
  3064. #
  3065. # ***********************************************************************************
  3066.  
  3067. class ScrollPrinterInfoView(ScrollView):
  3068.     def __init__(self, service, parent = None, form=None, name = None,fl = 0):
  3069.         ScrollView.__init__(self, service, parent, name, fl)
  3070.  
  3071.  
  3072.     def fillControls(self):
  3073.         ScrollView.fillControls(self)
  3074.  
  3075.         printers = []
  3076.         for p in self.printers:
  3077.             if p.device_uri == self.cur_device.device_uri: 
  3078.                 printers.append(p)
  3079.  
  3080.         if not printers:
  3081.             self.addGroupHeading("error_title", self.__tr("No printers found for this device."))
  3082.         else:
  3083.             for p in printers:
  3084.                 self.addPrinterInfo(p)
  3085.  
  3086.         self.maximizeControl()
  3087.  
  3088.  
  3089.     def addPrinterInfo(self, p):
  3090.         self.addGroupHeading(p.name, p.name)
  3091.         widget = self.getWidget()
  3092.  
  3093.         layout1 = QVBoxLayout(widget,5,10,"layout1")
  3094.  
  3095.         textLabel2 = QLabel(widget,"textLabel2")
  3096.  
  3097.         if p.device_uri.startswith("hpfax:"):
  3098.             s = self.__tr("Fax")
  3099.         else:
  3100.             s = self.__tr("Printer")
  3101.  
  3102.         textLabel2.setText(self.__tr("Type: %1").arg(s))
  3103.         layout1.addWidget(textLabel2)
  3104.  
  3105.         textLabel3 = QLabel(widget,"textLabel3")
  3106.         textLabel3.setText(self.__tr("Location: %1").arg(p.location))
  3107.         layout1.addWidget(textLabel3)
  3108.  
  3109.         textLabel4 = QLabel(widget,"textLabel4")
  3110.         textLabel4.setText(self.__tr("Description/Info: %1").arg(p.info))
  3111.         layout1.addWidget(textLabel4)
  3112.  
  3113.         textLabel5 = QLabel(widget,"textLabel5")
  3114.  
  3115.         if p.state == cups.IPP_PRINTER_STATE_IDLE:
  3116.             s = self.__tr("Idle")
  3117.         elif p.state == cups.IPP_PRINTER_STATE_PROCESSING:
  3118.             s = self.__tr("Processing")
  3119.         elif p.state == cups.IPP_PRINTER_STATE_STOPPED:
  3120.             s = self.__tr("Stopped")
  3121.         else:
  3122.             s = self.__tr("Unknown")
  3123.  
  3124.         textLabel5.setText(self.__tr("State: %1").arg(s))
  3125.         layout1.addWidget(textLabel5)
  3126.  
  3127.         textLabel6 = QLabel(widget,"textLabel6")
  3128.         textLabel6.setText(self.__tr("PPD/Driver: %1").arg(p.makemodel))
  3129.         layout1.addWidget(textLabel6)
  3130.  
  3131.         textLabel7 = QLabel(widget,"textLabel7")
  3132.         textLabel7.setText(self.__tr("CUPS/IPP Printer URI: %1").arg(p.printer_uri))
  3133.         layout1.addWidget(textLabel7)
  3134.  
  3135.         self.addWidget(widget, p.name)
  3136.  
  3137.  
  3138.     def __tr(self,s,c = None):
  3139.         return qApp.translate("ScrollPrinterInfoView",s,c)
  3140.  
  3141.  
  3142.  
  3143.  
  3144. # ***********************************************************************************
  3145. #
  3146. # Color cal type 7
  3147. #
  3148. # ***********************************************************************************
  3149.  
  3150. class ScrollColorCalView(ScrollView):
  3151.     def __init__(self, service, parent = None, form=None, name = None,fl = 0):
  3152.         ScrollView.__init__(self, service, parent, name, fl)
  3153.         self.dialog = parent
  3154.  
  3155.  
  3156.     def fillControls(self):
  3157.         ScrollView.fillControls(self)
  3158.         self.addLoadPaper(PAPER_TYPE_HP_ADV_PHOTO)
  3159.  
  3160.         self.printButton = self.addActionButton("bottom_nav", self.__tr("Perform Color Calibration"), 
  3161.             self.colorcalButton_clicked, 'print.png', None)
  3162.  
  3163.  
  3164.     def colorcalButton_clicked(self):
  3165.         d = self.cur_device
  3166.         printer_name = self.cur_printer
  3167.         printed = False
  3168.  
  3169.         try:
  3170.             QApplication.setOverrideCursor(QApplication.waitCursor)
  3171.  
  3172.             try:
  3173.                 d.open()
  3174.             except Error:
  3175.                 self.CheckDeviceUI()
  3176.             else:
  3177.                 if d.isIdleAndNoError():
  3178.                     QApplication.restoreOverrideCursor()
  3179.                     d.close()
  3180.  
  3181.                     d.setPML(pml.OID_PRINT_INTERNAL_PAGE, pml.PRINT_INTERNAL_PAGE_AUTOMATIC_COLOR_CALIBRATION)
  3182.                     printed = True
  3183.  
  3184.                 else:
  3185.                     d.close()
  3186.                     self.CheckDeviceUI()
  3187.  
  3188.         finally:
  3189.             QApplication.restoreOverrideCursor()
  3190.  
  3191.         if printed:
  3192.             QMessageBox.information(self,
  3193.                 self.caption(),
  3194.                 self.__tr("<p><b>A test page should be printing on your printer.</b><p>If the page fails to print, please visit http://hplip.sourceforge.net for troubleshooting and support."),
  3195.                 QMessageBox.Ok,
  3196.                 QMessageBox.NoButton,
  3197.                 QMessageBox.NoButton)
  3198.  
  3199.         self.dialog.accept()
  3200.  
  3201.  
  3202.     def CheckDeviceUI(self):
  3203.             self.FailureUI(self.__tr("<b>Device is busy or in an error state.</b><p>Please check device and try again."))      
  3204.       
  3205.     
  3206.     def FailureUI(self, error_text):
  3207.         QMessageBox.critical(self,
  3208.             self.caption(),
  3209.             error_text,
  3210.             QMessageBox.Ok,
  3211.             QMessageBox.NoButton,
  3212.             QMessageBox.NoButton)
  3213.       
  3214.  
  3215.